diff --git a/.gitmodules b/.gitmodules index 74d53404..8f4a4da8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,12 @@ [submodule "themes/anubis"] path = themes/anubis url = https://github.com/mitrichius/hugo-theme-anubis.git +[submodule "themes/black-and-light"] + path = themes/black-and-light + url = https://github.com/davidhampgonsalves/hugo-black-and-light-theme.git +[submodule "themes/anubis2"] + path = themes/anubis2 + url = https://github.com/Junyi-99/hugo-theme-anubis2.git +[submodule "themes/hugo-coder"] + path = themes/hugo-coder + url = https://github.com/rnemeth90/hugo-coder.git diff --git a/Screenshot 2024-09-04 at 11.13.40.png b/Screenshot 2024-09-04 at 11.13.40.png new file mode 100644 index 00000000..284f1d92 Binary files /dev/null and b/Screenshot 2024-09-04 at 11.13.40.png differ diff --git a/config.toml b/config.toml new file mode 100644 index 00000000..e1c3ae08 --- /dev/null +++ b/config.toml @@ -0,0 +1,109 @@ +languageCode = "en-us" +name = "GeekyRyan" +baseUrl = "https://rnemeth90.github.io" +title = "GeekyRyan" +theme = "hugo-coder" +paginate = 10 +enableRobotsTXT = true + +[pagination] +pagerSize = 10 # Added field from Coder theme + +[services] +[services.disqus] +# Enable Disqus comments +# shortname = "yourdiscussshortname" # Added section from Coder theme + +[markup.highlight] +style = "base16-snazzy" +noClasses = false # Added field from Coder theme + +[markup.goldmark.renderer] +unsafe = true # enable raw HTML in Markdown + +[params] +author = "Ryan Nemeth" +email = "ryannemeth@live.com" # used for microformats +avatar = "/images/bobble.jpg" # used for microformats +description = "Ryan Nemeth's personal website" +keywords = "blog,developer,personal,devops" +info = ["Full Stack DevOps Engineer"] +avatarURL = "images/bobble.jpg" # +dateFormat = "2006-01-02" +name = "GeekyRyan" +paginationSinglePost = true +style = "dark" +readMore = true # show read more button +readNextPosts = 5 # show 5 related posts, 0 by default +disableSummary = false +copyCodeButton = true # true by default +rssAsSocialIcon = true +since = 2012 +rtl = false # Added from Coder theme +colorScheme = "auto" # Added from Coder theme +hideColorSchemeToggle = false # Added from Coder theme +maxSeeAlsoItems = 5 # Added from Coder theme +customCSS = [] # Added from Coder theme +customSCSS = [] # Added from Coder theme +customJS = [] # Added from Coder theme +customRemoteJS = [] # Added from Coder theme + +[[params.social]] +url = "https://github.com/rnemeth90/" +name = "Github" +icon = "fa-brands fa-github fa-2x" +weight = 1 + +# [[params.social]] +# name = "Twitter" +# icon = "fa-brands fa-x-twitter fa-2x" +# weight = 3 +# url = "https://twitter.com/johndoe/" # Added from Coder theme + +[[params.social]] +name = "LinkedIn" +icon = "fa-brands fa-linkedin fa-2x" +weight = 2 +url = "https://www.linkedin.com/in/ryan-nemeth-b0b1504b/" + +[[params.social]] +name = "RSS" +icon = "fa-solid fa-rss fa-2x" +weight = 3 +url = "https://rnemeth90.github.io/index.xml" +rel = "alternate" +type = "application/rss+xml" # Added from Coder theme + +[taxonomies] +category = "categories" +tag = "tags" +series = "series" # Added from Coder theme +author = "authors" # Added from Coder theme + +[languages.en] +languageName = ":uk:" + +[[languages.en.menu.main]] +name = "About" +weight = 1 +url = "about/" + +[[languages.en.menu.main]] +name = "Blog" +weight = 2 +url = "posts/" + +[[languages.en.menu.main]] +name = "Projects" +weight = 3 +url = "projects/" + +[[languages.en.menu.main]] +name = "Tags" +url = "/tags/" +weight = 4 + +# [[languages.en.menu.main]] +# name = "Contact me" +# weight = 5 +# url = "contact/" diff --git a/config.yaml b/config.yaml deleted file mode 100644 index 23e04047..00000000 --- a/config.yaml +++ /dev/null @@ -1,85 +0,0 @@ -languageCode: "en-us" -baseUrl: "https://rnemeth90.github.io" -title: "GeekyRyan" -theme: "github.com/Mitrichius/hugo-theme-anubis" -paginate: 10 -#disqusShortname: "yourdiscussshortname" -#googleAnalytics: "G-12345" -enableRobotsTXT: true - -menu: - main: - - identifier: archive - name: Archive - title: Archive - url: /posts/ - weight: 3 - - identifier: about - name: About - title: about - url: /about - weight: 1 - - identifier: tags - name: Tags - title: tags - url: /tags/ - weight: 2 - -taxonomies: - category: "categories" - tag: "tags" - -params: - author: "Ryan Nemeth" - email: ryannemeth@live.com # used for microformats - avatar: "/images/bobble.jpg" # used for microformats - description: "" - # Uncomment if you need this - # images: - # - images/og-featured.png # relative path to "static" directory - # customCSS: - # - css/my.css # relative path to "assets" directory (don't use main.css filename) - # customJS: - # - js/main.js # relative path to "assets" directory - dateFormat: "2006-01-02" - paginationSinglePost: true - style: dark - readMore: true # show read more button - readNextPosts: 5 # show 5 related posts, 0 by default - disableSummary: false - copyCodeButton: true # true by default - rssAsSocialIcon: true - # utteranc.es support - utterancesRepo: "" # mandatory - utterancesTheme: "" # optional - utterancesIssue: "" # optional - utterancesLabel: "" # optional - # isso support - isso: - enabled: true # mandatory - data: "https://comments.example.com/" # mandatory - jsLocation: "https://comments.example.com/js/embed.min.js" # mandatory - css: true # optional - lang: "de" # optional - replyToSelf: true # mandatory - requireAuthor: true # mandatory - requireEmail: true # mandatory - id: "thread-id" # optional - avatar: true # optional - avatar-bg: "#f0f0f0" # optional - feed: false # optional - graphcommentId: "" - webmentions: - url: https://yourdomain.com/webemntions/receive - login: hugo-theme-anubis - pingback: true - social: - - id: github - name: rnemeth90 - - id: twitter - name: geeky_ryan - -markup: - goldmark: - renderer: - unsafe: true # enable raw HTML in Markdown diff --git a/config.yaml.old b/config.yaml.old new file mode 100644 index 00000000..90d32c90 --- /dev/null +++ b/config.yaml.old @@ -0,0 +1,72 @@ +languageCode: 'en-us' +name: 'GeekyRyan' +baseUrl: 'https://rnemeth90.github.io' +title: 'GeekyRyan' +theme: 'anubis2' +paginate: 10 +enableRobotsTXT: true + +menu: + main: + - identifier: archive + name: Archive + title: Archive + url: /posts/ + weight: 3 + - identifier: about + name: About + title: about + url: /about + weight: 1 + - identifier: tags + name: Tags + title: tags + url: /tags/ + weight: 2 + +taxonomies: + category: 'categories' + tag: 'tags' + +params: + author: 'Ryan Nemeth' + email: ryannemeth@live.com # used for microformats + avatar: '/images/bobble.jpg' # used for microformats + description: '' + dateFormat: '2006-01-02' + name: 'GeekyRyan' + paginationSinglePost: true + style: dark + readMore: true # show read more button + readNextPosts: 5 # show 5 related posts, 0 by default + disableSummary: false + copyCodeButton: true # true by default + rssAsSocialIcon: true + utterancesRepo: '' # mandatory + utterancesTheme: '' # optional + utterancesIssue: '' # optional + utterancesLabel: '' # optional + isso: + enabled: true # mandatory + data: 'https://comments.example.com/' # mandatory + jsLocation: 'https://comments.example.com/js/embed.min.js' # mandatory + css: true # optional + lang: 'de' # optional + replyToSelf: true # mandatory + requireAuthor: true # mandatory + requireEmail: true # mandatory + id: 'thread-id' # optional + avatar: true # optional + avatar-bg: '#f0f0f0' # optional + feed: false # optional + graphcommentId: '' + social: + - id: github + name: rnemeth90 + +markup: + highlight: + style: 'base16-snazzy' + goldmark: + renderer: + unsafe: true # enable raw HTML in Markdown diff --git a/content/images/acr-403-02.png b/content/images/acr-403-02.png new file mode 100644 index 00000000..284f1d92 Binary files /dev/null and b/content/images/acr-403-02.png differ diff --git a/content/images/acr-403.png b/content/images/acr-403.png new file mode 100644 index 00000000..0202193d Binary files /dev/null and b/content/images/acr-403.png differ diff --git a/content/posts/2024-03-27-golang-detect-file-type.md b/content/posts/2024-03-27-golang-detect-file-type.md new file mode 100644 index 00000000..7c14daf2 --- /dev/null +++ b/content/posts/2024-03-27-golang-detect-file-type.md @@ -0,0 +1,56 @@ +--- +title: 'Detecting MIME Types in Go' +author: Ryan +date: '2024-03-27' +layout: post +draft: false +categories: + - golang + - web development + - software development +tags: + - golang + - web development + - software development + - url +--- + +# Introduction + +Knowing the type of a file you're working with is not just a matter of curiosity — it's often a necessity. This is especially true when you're deciding whether or not a particular operation can be carried out on that file. Go, with its comprehensive standard library, offers a straightforward approach to identifying a file's MIME type, ensuring that developers have the tools they need to make informed decisions about file manipulation. You may expect to find this functionality in the `file` package, but you'd be wrong! Read on... + +## The net/http Package: Your Gateway to MIME Detection + +At the heart of Go's approach to MIME type detection is the `net/http` package. This package provides everything developers need for identifying file types. The method in question, `DetectContentType()`, is nothing short of a detective dedicated to uncovering the secrets held within the first 512 bytes of a file. + +Imagine you're downloading an image for processing from a URL, but before you proceed, you need to confirm its type. Here's how you'd *go* about it: + +``` +resp, err := client.Get("https://rnemeth90.github.io/images/synology-cloud-sync-01.png") +if err != nil { + log.Fatal(err) +} +defer resp.Body.Close() + +bytes, err := ioutil.ReadAll(resp.Body) +if err != nil { + log.Fatal(err) +} + +// detecting the MIME type +mimeType := http.DetectContentType(bytes) +fmt.Println(mimeType) // Voila! It's an image/png +``` + +In this snippet, `DetectContentType()` takes the stage, examining the initial bytes of the file and returning a MIME type, such as `image/png`. Should it find itself at a loss, unable to pin down the file's type, it defaults to `application/octet-stream`, a way of saying, "This is a file, but beyond that, you're on your own." + +# Beyond the Basics: When You Need More + +While `DetectContentType()` serves well for a number of common file types, its repertoire is not unlimited. There are scenarios where you might find yourself needing to identify more obscure or specific file types. This is where the mimetype library steps in, offering a more extensive catalog of file types. If `DetectContentType()` isn't able to help you, considering this library might just be your next move. + +# Conclusion + +Go's `net/http` package, with its `DetectContentType()` method, provides a solid foundation for this task. And for those times when you need to *go* further, the `mimetype` library is there to help. + +Whether you're safeguarding against the wrong file types in an upload process or curating content based on its nature, understanding and utilizing MIME type detection is an invaluable skill. Thanks for reading! + diff --git a/content/posts/2024-06-29-mount multiple Kubernetes secrets into one directory.md b/content/posts/2024-06-29-mount multiple Kubernetes secrets into one directory.md new file mode 100644 index 00000000..4cdf9582 --- /dev/null +++ b/content/posts/2024-06-29-mount multiple Kubernetes secrets into one directory.md @@ -0,0 +1,68 @@ +--- +title: 'Mounting Multiple Kubernetes Secrets into One Directory' +author: Ryan +date: '2024-06-29' +layout: post +draft: false +categories: + - Kubernetes +tags: + - devops + - web development + - software development +--- + +# Introduction + +Combining multiple Kubernetes secrets into a single directory can streamline secret management in your applications. This guide walks you through the process of achieving this in Kubernetes, ensuring efficient and organized secret management. + +# Creating Secrets + +First, create your secrets using the `kubectl create secret` command: + +``` +kubectl create secret generic secret-one --from-literal=key1=value1 +kubectl create secret generic secret-two --from-literal=key2=value2 +``` + +Each secret can contain multiple key-value pairs, and you can add more secrets as needed. + +# Configuring the Pod + +Next, define the pod configuration to mount these secrets into a single directory. Here’s an example configuration: + +``` +apiVersion: v1 +kind: Pod +metadata: + name: mypod +spec: + containers: + - name: mycontainer + image: myimage + volumeMounts: + - name: secret-volume1 + mountPath: "/etc/secrets/secret-one" + subPath: key1 + - name: secret-volume2 + mountPath: "/etc/secrets/secret-two" + subPath: key2 + volumes: + - name: secret-volume1 + secret: + secretName: secret-one + - name: secret-volume2 + secret: + secretName: secret-two +``` + +# Detailed Explanation + +- Volume Mounts: The `volumeMounts` section specifies where the secrets will be mounted within the container's file system. By using the `subPath` property, you can place each secret's content into a specific file within the target directory. +- Volumes: The volumes section links each volume to a Kubernetes secret. This ensures that the secrets are available to the container at runtime. + +In this example, secret-one and secret-two are mounted into `/etc/secrets/secret-one` and `/etc/secrets/secret-two`, respectively. The `subPath` ensures that each key-value pair from the secrets is mapped to a separate file within the specified directory. + +# Conclusion + +By mounting secrets into subdirectories using the `subPath` property, you can effectively manage multiple secrets within a single directory. This method enhances organization and accessibility, making it easier to handle secrets in your Kubernetes applications. diff --git a/content/posts/2024-09-04-azure-container-registry-403.md b/content/posts/2024-09-04-azure-container-registry-403.md new file mode 100644 index 00000000..02ebec7b --- /dev/null +++ b/content/posts/2024-09-04-azure-container-registry-403.md @@ -0,0 +1,22 @@ +--- +title: 'Mounting Multiple Kubernetes Secrets into One Directory' +author: Ryan +date: '2024-06-29' +layout: post +draft: true +categories: + - Kubernetes +tags: + - devops + - web development + - software development +--- + +# Introduction + +``` + +``` + +[![](https://rnemeth90.github.io/images/acr-403.png)](https://rnemeth90.github.io/images/acr-403.png) +[![](https://rnemeth90.github.io/images/acr-403-02.png)](https://rnemeth90.github.io/images/acr-403-02.png) diff --git a/content/posts/2024-12-05-dotnet-console-app-health-probe.md b/content/posts/2024-12-05-dotnet-console-app-health-probe.md new file mode 100644 index 00000000..e2694a1e --- /dev/null +++ b/content/posts/2024-12-05-dotnet-console-app-health-probe.md @@ -0,0 +1,106 @@ +--- +title: 'Kubernetes Health Probing in Dotnet Console Apps' +author: Ryan +date: '2024-12-05' +layout: post +draft: false +categories: + - Kubernetes +tags: + - devops + - software development + - dotnet + - sre +--- + +# Introduction + +This post covers a simple and efficient solution for implementing liveness probes in pods running console applications (think background services or utility DaemonSets). A common question I see in Kubernetes forums is: + + “How do I use health probes with console apps?” + +The typical responses often suggest: + +1. Sidecar Container with HTTP Server: Requires coding the server, building a sidecar container, and managing additional infrastructure. While effective, this can be overkill for lightweight applications. +2. Exec Probes with Shell Scripts: Feels hacky and can waste resources, depending on what the script does. + +Pods are meant to be lightweight, and both solutions can deviate from that principle. + +Instead, we’ll use a simple TCP listener to create an efficient liveness probe. Here’s the code: + +``` +using System; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; + +class Program +{ + static void Main(string[] args) + { + int port = 666; // You can run this on a different port if necessary + + Thread tcpServerThread = new Thread(() => StartTcpServer(port)); + tcpServerThread.IsBackground = true; + tcpServerThread.Start(); + + Console.WriteLine("Application is running..."); + while (true) + { + // do some work + Thread.Sleep(1000); + } + } + + static void StartTcpServer(int port) + { + TcpListener server = null; + + try + { + server = new TcpListener(IPAddress.Any, port); + server.Start(); + Console.WriteLine($"Liveness server started on port {port}."); + + while (true) + { + TcpClient client = server.AcceptTcpClient(); + NetworkStream stream = client.GetStream(); + + byte[] buffer = new byte[256]; + int bytesRead = stream.Read(buffer, 0, buffer.Length); + string request = Encoding.ASCII.GetString(buffer, 0, bytesRead).Trim(); + + if (request.Equals("ping", StringComparison.OrdinalIgnoreCase)) + { + byte[] response = Encoding.ASCII.GetBytes("pong\n"); + stream.Write(response, 0, response.Length); + } + + client.Close(); + } + } + catch (Exception ex) + { + Console.WriteLine($"Error in liveness server: {ex.Message}"); + } + finally + { + server?.Stop(); + } + } +} +``` + +The StartTcpServer() method starts a simple TCP server in a thread running concurrent to the main thread. Use a `tcpSocket` liveness probe in your Kubernetes manifest. Kubernetes will then attempt to establish a TCP connection at configured intervals. You can test it by doing the same, or using a tool like `netcat`: + +``` +echo "ping" | nc localhost 666 +``` + +'pong' should be returned. + +Simply add this TCP server to your application and then configure the liveness probe. Examples can be found in the Kubernetes docs linked below. + +https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ diff --git a/public/404.html b/public/404.html index 37a698d1..c6e7f65b 100644 --- a/public/404.html +++ b/public/404.html @@ -1,337 +1,110 @@ - + + - - - - - - - - - -404 Page not found - GeekyRyan - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + GeekyRyan + + + - + + + - + + + + + + + + + + + + + + - - - - - + - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - Skip to main content -
-
- -
-

- GeekyRyan -

- -
- -
-
- -
-
-

Go Home

- Sorry, this Page is not available. -
-
- -
- - - - -
+ + diff --git a/public/about/index.html b/public/about/index.html index 86592758..57bfa5a9 100644 --- a/public/about/index.html +++ b/public/about/index.html @@ -1,115 +1,79 @@ + - - - - - - - + + + About · GeekyRyan + + - - -About - GeekyRyan - - - - - + - - - - - - - - - + + + + + + + + + + + + - - - - - - - - + + + + - - + + + - - - - - + - + + + - - - - - - - - - - - - + + + + + - - - - - - - - - + + @@ -119,342 +83,200 @@ - - - Skip to main content -
-
- -
-

- GeekyRyan -

- -
- - - - - - - - - -
-
- + + + + -
-
-
-

About

+
+ +
+
-
-
- drawing + drawing

My name is Ryan Nemeth and this is my personal blog. I write down my thoughts regarding Microsoft Azure, Kubernetes, cloud-native technologies, and software development. I find that documenting these things not only helps others but also helps reinforce my own knowledge as well. I may also blog about life or other random things from time to time.

This blog has had many lives over the years. It originally started as a Blogger blog way back in 2012, moved to Wordpress for a while, then back to blogger, then to Ghost (running on a small droplet over @ DigitalOcean), then back to Wordpress again, and now here on Github pages. That’s a lot of change (such is life)! So if you happen to come across a page that has some weird formatting, missing images, etc. Please be kind and let me know so that I may fix it.

I’m currently working remote as a Senior DevOps Engineer/SRE for Aprimo on the Systems team.

Before joining Aprimo, I was a cloud architect for a software company specializing in HCM software.

The opinions expressed here are my own personal opinions, and do not represent my employer’s view in any way.

-

Contact me through LinkedIn or Github. +

Contact me through LinkedIn or Github.

-

Currently Reading: - - - - - -

- - - - - -
+ + -
- -
-
- - + + -
- - -
-
-
-
+ + + + + + + - + + - - - + - - + + diff --git a/public/authors/index.html b/public/authors/index.html new file mode 100644 index 00000000..a44168f1 --- /dev/null +++ b/public/authors/index.html @@ -0,0 +1,111 @@ + + + + + + Authors · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ + +
+
+
+

+ Authors +

+
+ +
    +
    +
    + + +
    + + + + + diff --git a/public/authors/index.xml b/public/authors/index.xml new file mode 100644 index 00000000..68f5ca70 --- /dev/null +++ b/public/authors/index.xml @@ -0,0 +1,11 @@ + + + + Authors on GeekyRyan + http://localhost:1313/authors/ + Recent content in Authors on GeekyRyan + Hugo + en + + + diff --git a/public/categories/.net-core/index.html b/public/categories/.net-core/index.html index 288dc9b5..c962526f 100644 --- a/public/categories/.net-core/index.html +++ b/public/categories/.net-core/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: .NET Core · GeekyRyan + - - -.NET Core - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,306 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Category: .NET Core

    - - - -
    -
    -
    -

    EF Core – Unable to create an object of type DbContext

    -
    -
    +
    +
    + © -
    - This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it! -When running EF Core migrations in a solution, you may come across this error: -There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio. -To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - - + + diff --git a/public/categories/.net-core/index.xml b/public/categories/.net-core/index.xml index 857b582c..c7271691 100644 --- a/public/categories/.net-core/index.xml +++ b/public/categories/.net-core/index.xml @@ -2,31 +2,18 @@ .NET Core on GeekyRyan - https://rnemeth90.github.io/categories/.net-core/ - GeekyRyan (.NET Core) - Hugo -- gohugo.io - en-us + http://localhost:1313/categories/.net-core/ + Recent content in .NET Core on GeekyRyan + Hugo + en Sun, 12 Jun 2022 13:58:52 +0000 - - - - + EF Core &#8211; Unable to create an object of type DbContext - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ Sun, 12 Jun 2022 13:58:52 +0000 - - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ - <p>This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it!</p> -<p>When running EF Core migrations in a solution, you may come across this error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-1-1024x142.png"></a></p> -<p>There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio.</p> -<p>To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-2.png"></a></p> -<p>If you are using clean architecture, or some other architecture that has your startup context and your dbContext in different projects, you will need to set your startup project to your runtime, and the ‘Default Project’ in the package manager console to the project containing your dbContext.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-3-1024x493.png"></a></p> - + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it! When running EF Core migrations in a solution, you may come across this error: There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio. To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’. - diff --git a/public/categories/.net-core/page/1/index.html b/public/categories/.net-core/page/1/index.html index 7dfa94c9..f2b90c89 100644 --- a/public/categories/.net-core/page/1/index.html +++ b/public/categories/.net-core/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/.net-core/ - + http://localhost:1313/categories/.net-core/ + - + diff --git a/public/categories/.net/index.html b/public/categories/.net/index.html index 73a312c1..46b3e59a 100644 --- a/public/categories/.net/index.html +++ b/public/categories/.net/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: .NET · GeekyRyan + - - -.NET - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,306 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Category: .NET

    - - - -
    -
    -
    -

    EF Core &#8211; Unable to create an object of type DbContext

    -
    -
    +
    +
    + © -
    - This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it! -When running EF Core migrations in a solution, you may come across this error: -There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio. -To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - - + + diff --git a/public/categories/.net/index.xml b/public/categories/.net/index.xml index 2b858517..c02021f3 100644 --- a/public/categories/.net/index.xml +++ b/public/categories/.net/index.xml @@ -2,31 +2,18 @@ .NET on GeekyRyan - https://rnemeth90.github.io/categories/.net/ - GeekyRyan (.NET) - Hugo -- gohugo.io - en-us + http://localhost:1313/categories/.net/ + Recent content in .NET on GeekyRyan + Hugo + en Sun, 12 Jun 2022 13:58:52 +0000 - - - - + EF Core &#8211; Unable to create an object of type DbContext - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ Sun, 12 Jun 2022 13:58:52 +0000 - - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ - <p>This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it!</p> -<p>When running EF Core migrations in a solution, you may come across this error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-1-1024x142.png"></a></p> -<p>There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio.</p> -<p>To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-2.png"></a></p> -<p>If you are using clean architecture, or some other architecture that has your startup context and your dbContext in different projects, you will need to set your startup project to your runtime, and the ‘Default Project’ in the package manager console to the project containing your dbContext.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-3-1024x493.png"></a></p> - + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it! When running EF Core migrations in a solution, you may come across this error: There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio. To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’. - diff --git a/public/categories/.net/page/1/index.html b/public/categories/.net/page/1/index.html index 96c64715..8026f79d 100644 --- a/public/categories/.net/page/1/index.html +++ b/public/categories/.net/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/.net/ - + http://localhost:1313/categories/.net/ + - + diff --git a/public/categories/azure-devops/index.html b/public/categories/azure-devops/index.html index 88aeb7f6..4c34a495 100644 --- a/public/categories/azure-devops/index.html +++ b/public/categories/azure-devops/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: Azure Devops · GeekyRyan + - - -Azure Devops - GeekyRyan - - - - - - - - - - + - - + + + - - + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,364 +79,161 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    -
    -
    - -

    Category: Azure Devops

    - + 2022-11-03 + Chaining YAML Pipelines in Azure Devops + +
  • + 2022-09-12 + Update Azure Devops SPN Secret +
  • -
    -
    -
    -

    Chaining YAML Pipelines in Azure Devops

    -
    - -
    + + - -
    - In this article, we’ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to figure this out. -Our two pipelines will exist in the same repository. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Update Azure Devops SPN Secret

    -
    -
    +
    +
    + © -
    - If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal. -In this article, I’ll show you two methods for updating a secret for a service principal prior to expiration. -Update the secret via the Azure Devops Portal: Go to “Service Connections” in the Azure Devops portal Find the SPN you want to update, then click “Manage Service Principal” Then on the service principal page, click Certificates & Secrets Create a “New Client Secret”, take note of the value Delete the ‘old’ secret Return to the Service Connection in the Azure Devops portal Click Edit - click the verify button. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - +
    +
    -
    - https://rnemeth90.github.io/posts/2022-09-12-update-azure-devops-spn-secret/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - - + + diff --git a/public/categories/azure-devops/index.xml b/public/categories/azure-devops/index.xml index 2d715b75..b62df6d4 100644 --- a/public/categories/azure-devops/index.xml +++ b/public/categories/azure-devops/index.xml @@ -2,101 +2,25 @@ Azure Devops on GeekyRyan - https://rnemeth90.github.io/categories/azure-devops/ - GeekyRyan (Azure Devops) - Hugo -- gohugo.io - en-us + http://localhost:1313/categories/azure-devops/ + Recent content in Azure Devops on GeekyRyan + Hugo + en Thu, 03 Nov 2022 00:00:00 +0000 - - - - + Chaining YAML Pipelines in Azure Devops - https://rnemeth90.github.io/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ + http://localhost:1313/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ Thu, 03 Nov 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ - <p>In this article, we&rsquo;ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. -Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to -figure this out.</p> -<p>Our two pipelines will exist in the same repository. We have a dependent-pipeline, that we only want to run once the source-pipeline is finished. This is useful if you have -some infrastructure you want to build, prior to deploying something to that infrastructure.</p> -<p>The process is actually quite simple. First, let&rsquo;s define our source pipeline:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># source-pipeline</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: <span style="color:#ae81ff">echo Hello, world!</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a one-line script&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo Add other tasks to build, test, and deploy your project. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo See https://aka.ms/yaml</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a multi-line script&#39;</span> -</span></span></code></pre></div><p>Nothing fancy here, just the build in template pipeline that Microsoft gives us for free when we create a &ldquo;Starter Pipeline&rdquo;.</p> -<p>Now, let&rsquo;s create another pipeline in the same repo that will be triggered when the pipeline above completes:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># dependent-pipeline</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">none</span> <span style="color:#75715e"># we want this pipeline to be triggered manually, not based on PR, etc.</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">pipelines</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">pipeline</span>: <span style="color:#ae81ff">source-pipeline</span> <span style="color:#75715e">#this can be anything</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">source</span>: <span style="color:#e6db74">&#39;source-pipeline&#39;</span> <span style="color:#75715e">#this needs to be the name of the &#39;source&#39; pipeline</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">trigger</span>: <span style="color:#66d9ef">true</span> <span style="color:#75715e"># Run dependent-pipeline pipeline when any run of security-lib-ci completes</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: <span style="color:#ae81ff">echo Hello, world!</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a one-line script&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo Add other tasks to build, test, and deploy your project. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo See https://aka.ms/yaml</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a multi-line script&#39;</span> -</span></span></code></pre></div><p>The resources block above defines our dependency. You want to be sure to configure the trigger of the dependent pipeline appropriately as well.</p> -<p>There are several options for fine-tuning this process. See the office Microsoft documentation below:</p> -<p><a href="https://learn.microsoft.com/en-us/azure/devops/pipelines/process/pipeline-triggers?view=azure-devops">Link to the Microsoft Docs</a></p> - + http://localhost:1313/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ + In this article, we&rsquo;ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to figure this out. Our two pipelines will exist in the same repository. - Update Azure Devops SPN Secret - https://rnemeth90.github.io/posts/2022-09-12-update-azure-devops-spn-secret/ + http://localhost:1313/posts/2022-09-12-update-azure-devops-spn-secret/ Mon, 12 Sep 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-09-12-update-azure-devops-spn-secret/ - <p>If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal.</p> -<p>In this article, I&rsquo;ll show you two methods for updating a secret for a service principal prior to expiration.</p> -<h1 id="update-the-secret-via-the-azure-devops-portal" >Update the secret via the Azure Devops Portal: -<span> - <a href="#update-the-secret-via-the-azure-devops-portal"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h1><ul> -<li>Go to &ldquo;Service Connections&rdquo; in the Azure Devops portal</li> -<li>Find the SPN you want to update, then click &ldquo;Manage Service Principal&rdquo;</li> -<li>Then on the service principal page, click Certificates &amp; Secrets</li> -<li>Create a &ldquo;New Client Secret&rdquo;, take note of the value</li> -<li>Delete the &lsquo;old&rsquo; secret</li> -<li>Return to the Service Connection in the Azure Devops portal</li> -<li>Click Edit - click the verify button. It should tell you the client certificate has expired</li> -<li>Now you need to make an arbitrary change and save it. I just type a character in the optional description and save.</li> -<li>Now edit again and click verify, it will now pick up the new client secret and all is happy.</li> -<li>You can now remove whatever you added to the description.</li> -</ul> - + http://localhost:1313/posts/2022-09-12-update-azure-devops-spn-secret/ + If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal. In this article, I&rsquo;ll show you two methods for updating a secret for a service principal prior to expiration. Update the secret via the Azure Devops Portal: Link to heading Go to &ldquo;Service Connections&rdquo; in the Azure Devops portal Find the SPN you want to update, then click &ldquo;Manage Service Principal&rdquo; Then on the service principal page, click Certificates &amp; Secrets Create a &ldquo;New Client Secret&rdquo;, take note of the value Delete the &lsquo;old&rsquo; secret Return to the Service Connection in the Azure Devops portal Click Edit - click the verify button. - diff --git a/public/categories/azure-devops/page/1/index.html b/public/categories/azure-devops/page/1/index.html index 35ee8482..8493bc3a 100644 --- a/public/categories/azure-devops/page/1/index.html +++ b/public/categories/azure-devops/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/azure-devops/ - + http://localhost:1313/categories/azure-devops/ + - + diff --git a/public/categories/azure-kubernetes-service/index.html b/public/categories/azure-kubernetes-service/index.html index 5f148dbf..24648c94 100644 --- a/public/categories/azure-kubernetes-service/index.html +++ b/public/categories/azure-kubernetes-service/index.html @@ -1,849 +1,264 @@ + - - - - - - - + + Category: Azure Kubernetes Service · GeekyRyan + - + -Azure Kubernetes Service - GeekyRyan - + + + - - - + + + + + + + + + - - - - + + + + + + + - - - - - - - - - + - + + + - - - - - - - - - - + + + + + + + - - - - + - - - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - -
    -
    - -

    Category: Azure Kubernetes Service

    - - - -
    -
    -
    -

    AKS Scale Down Mode

    -
    - -
    - - -
    - By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete or deallocate nodes. -Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Scheduled Kubernetes Worker Node Maintenance with Kured

    -
    - -
    - - -
    - If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this? -Weaveworks created a great tool for simplifying these steps: Kured (the Kubernetes Reboot Daemon). -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Running Docker in WSL v1

    -
    - -
    - - -
    - I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. -Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Remove Kubernetes Namespace Stuck in the Terminating State

    -
    - -
    - - -
    - In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state. -A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. -
    - - -
    - Read more -
    - - - - - - - -
    - -
    -
    -
    -

    Kubernetes Storage Simplified

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Category: Azure Kubernetes Service +

    +
    + +
    +
  • + 2022-01-16 + Azure Kubernetes sFTP Solution +
  • -
    -
    -
    -

    Kubernetes Pod Eviction

    -
    - -
    + + - -
    - In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation. -What is Pod Eviction? Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Azure Kubernetes sFTP Solution

    -
    -
    +
    +
    + © -
    - In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault. -Here is the link to my Github account where you can download the code mentioned in this article: -https://github.com/rnemeth90/kubernetes-sftp -We will work through the following steps in this article: -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - - + + diff --git a/public/categories/azure-kubernetes-service/index.xml b/public/categories/azure-kubernetes-service/index.xml index ed2b3e09..c99d15f7 100644 --- a/public/categories/azure-kubernetes-service/index.xml +++ b/public/categories/azure-kubernetes-service/index.xml @@ -2,642 +2,60 @@ Azure Kubernetes Service on GeekyRyan - https://rnemeth90.github.io/categories/azure-kubernetes-service/ - GeekyRyan (Azure Kubernetes Service) - Hugo -- gohugo.io - en-us + http://localhost:1313/categories/azure-kubernetes-service/ + Recent content in Azure Kubernetes Service on GeekyRyan + Hugo + en Tue, 19 Jul 2022 00:00:00 +0000 - - - - + AKS Scale Down Mode - https://rnemeth90.github.io/posts/2022-07-19-aks-scale-down-mode/ + http://localhost:1313/posts/2022-07-19-aks-scale-down-mode/ Tue, 19 Jul 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-07-19-aks-scale-down-mode/ - <p>By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete <em>or</em> deallocate nodes.</p> -<p>Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. However, you will still need to pay for any storage that the node is using. Having persistent storage also means that any container images that were cached on the node will still be there when the node starts back up. This can be a major performance benefit if you are using Windows containers because the images for these containers are typically very large.</p> -<p>Scale down mode can be configured in several ways. Here, we will look at configuring it via the Azure CLI and Terraform.</p> -<p>Azure CLI:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>az aks nodepool update --scale-down-mode Deallocate --name nplinux01 --cluster-name myAKSCluster --resource-group myResourceGroup -</span></span></code></pre></div><p>Terraform:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-hcl" data-lang="hcl"><span style="display:flex;"><span><span style="color:#66d9ef">resource</span> <span style="color:#e6db74">&#34;azurerm_kubernetes_cluster_node_pool&#34; &#34;nodepool&#34;</span> { -</span></span><span style="display:flex;"><span> name <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;nplinux01&#34;</span> -</span></span><span style="display:flex;"><span> kubernetes_cluster_id <span style="color:#f92672">=</span> <span style="color:#66d9ef">azurerm_kubernetes_cluster</span>.<span style="color:#66d9ef">example</span>.<span style="color:#66d9ef">id</span> -</span></span><span style="display:flex;"><span> vm_size <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Standard_DS2_v2&#34;</span> -</span></span><span style="display:flex;"><span> node_count <span style="color:#f92672">=</span> <span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span> scale_down_mode <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Deallocate&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> tags <span style="color:#f92672">=</span> { -</span></span><span style="display:flex;"><span> Environment <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;lab&#34;</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><em>At the time of this writing, Terraform does not support configuring scale-down mode for the default AKS node pool.</em> -<em>Node pools using ephemeral disks do not support &lsquo;deallocate&rsquo; mode</em></p> - + http://localhost:1313/posts/2022-07-19-aks-scale-down-mode/ + By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete or deallocate nodes. Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. - Scheduled Kubernetes Worker Node Maintenance with Kured - https://rnemeth90.github.io/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ + http://localhost:1313/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ Fri, 15 Jul 2022 18:18:50 +0000 - - https://rnemeth90.github.io/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ - <p>If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this?</p> -<p>Weaveworks created a great tool for simplifying these steps: Kured (the <em><strong>Ku</strong>bernetes <strong>Re</strong>boot <strong>D</strong>aemon</em>). Let’s start by deploying Kured to our cluster.</p> -<p>Kured can be deployed in one of several ways. In this article, we’ll focus on deploying it via Helm. This is the simplest and quickest way to get it running in our cluster.</p> -<p>Follow these steps to install the Helm chart:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># 1) Add the Kured Helm repository</span> -</span></span><span style="display:flex;"><span>helm repo add kured https://weaveworks.github.io/kured -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 2) Update your local Helm chart repository cache</span> -</span></span><span style="display:flex;"><span>helm repo update -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 3) Create a dedicated namespace where you would like to deploy kured</span> -</span></span><span style="display:flex;"><span>kubectl create namespace kured -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 4) Install kured in that namespace with Helm 3 (only on Linux nodes)</span> -</span></span><span style="display:flex;"><span>helm install kured kured/kured --namespace kured --set nodeSelector.<span style="color:#e6db74">&#34;kubernetes\.io/os&#34;</span><span style="color:#f92672">=</span>linux -</span></span></code></pre></div><p>If all went well with the command above, that’s it, you’re done! Have a nice day! 🙂</p> -<p>If you want to test Kured, login to one of your Linux nodes, and install some patches with your package manager of choice (any patch that requires a reboot, typically patches that modify kernel headers). Then, check for a file named ‘reboot-required’ in /var/run:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>ls -lisa /var/run/reboot-required -</span></span></code></pre></div><p>If you installed patches, and this file does not exist, none of your patches require a reboot. We can still fake the system into thinking a reboot is required by manually creating the ‘reboot-required’ file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo touch /var/run/reboot-required -</span></span></code></pre></div><p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-1.png" alt=""></p> -<p>Then, we’ll use Kubetail to tail the logs of all our Kured pods:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubetail -label kured --namespace kured -</span></span></code></pre></div><p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-1024x749.png" alt=""></p> -<p>By default, Kured checks for the existence of the sentinel file every 60 minutes. However, this behavior can be changed. See the github repo for more info:</p> -<p><img src="https://github.com/weaveworks/kured#reboot-sentinel-file--period" alt="weaveworks/kured: Kubernetes Reboot Daemon"></p> -<p>Scheduling on the node should be disabled if you are within the Kured schedule</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-2.png" alt=""></p> -<p>Now that the node is cordoned off, running pods on the node are drained, and the node is rebooted.</p> -<p>That’s it for this article. Have a great day!</p> - + http://localhost:1313/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ + If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this? Weaveworks created a great tool for simplifying these steps: Kured (the Kubernetes Reboot Daemon). - Running Docker in WSL v1 - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ Sun, 26 Jun 2022 15:00:28 +0000 - - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ - <p>I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate.</p> -<p>Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. I receive this nice message:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ docker -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>The command <span style="color:#e6db74">&#39;docker&#39;</span> could not be found in this WSL <span style="color:#ae81ff">1</span> distro. -</span></span><span style="display:flex;"><span>We recommend to convert this distro to WSL <span style="color:#ae81ff">2</span> and activate -</span></span><span style="display:flex;"><span>the WSL integration in Docker Desktop settings. -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>See https://docs.docker.com/docker-for-windows/wsl/ <span style="color:#66d9ef">for</span> details. -</span></span></code></pre></div><p>So I’m in somewhat of a catch-22 here…</p> -<p>To work around this problem until a proper solution is found, I was able to get Docker working with WSL v1.</p> -<p>If you happen to be having a similar issue (and it seems like quite a few people are, considering the number of Github posts I found), just follow these steps:</p> -<ul> -<li>Expose the Docker daemon in docker desktop settings:</li> -</ul> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/02/image-10-1024x585.png"></a></p> -<p>Install the stand-alone Docker client in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ tar zxvf docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ cd docker -</span></span></code></pre></div><p>Set the default Docker daemon in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>export DOCKER_HOST<span style="color:#f92672">=</span>tcp://localhost:2375 -</span></span></code></pre></div><p>Verify you can connect to Docker running on Windows from within WSL:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>./docker info -</span></span></code></pre></div><p>This is also beneficial in that you only have one Docker host to manage your containers, network, etc., rather than two.</p> - + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ + I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. - Remove Kubernetes Namespace Stuck in the Terminating State - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ Sat, 04 Jun 2022 18:29:41 +0000 - - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ - <p>In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state.</p> -<p>A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. One day, you decide you no longer want this blog, so you plan to delete it. Rather than tediously deleting all of the various entities associated with this blog, you can delete the namespace that contains these entities. This will essentially ‘cascade delete’ the resources within the namespace as well.</p> -<p>After deleting the namespace for your blog, you notice that it still exists, but the state of it is ‘Terminating’, and it has been like this for a long time (hours or maybe even days).</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/06/image.png"></a></p> -<p>Kubernetes will occassionally fail to delete third-party resources when deleting a namespace, causing the namespace to linger. This can happen if the third-party API managing the resource is not responding to requests. To verify if any of these resources still exist, use this command:</p> -<pre tabindex="0"><code>kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get --show-kind --show-all --ignore-not-found -n &lt;terminating-namespace&gt; -</code></pre><p>If you happen to see any resources in the output, you can try force deleting them and then try to delete the namespace again.</p> -<p>In my experience, the majority of the time you will not find any resources still hanging around. Rather, the namespace will be completely empty. What is going on here?</p> -<p>Let’s take a look at the namespace:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ae81ff">$ kubectl get namespace darn-c101 -o yaml</span> -</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Namespace</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">annotations</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">kubectl.kubernetes.io/last-applied-configuration</span>: <span style="color:#ae81ff">|</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">kubernetes.io/metadata.name</span>: <span style="color:#ae81ff">darn-c101</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">finalizers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">kubernetes</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">status</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">conditions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">lastTransitionTime</span>: <span style="color:#e6db74">&#34;2022-06-01T19:05:31Z&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">message: &#39;Some content in the namespace has finalizers remaining</span>: <span style="color:#ae81ff">darn-c101.geekyryan.io/finalizer in 1 resource instances&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">reason</span>: <span style="color:#ae81ff">SomeFinalizersRemain</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">status</span>: <span style="color:#e6db74">&#34;True&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">NamespaceFinalizersRemaining</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">phase</span>: <span style="color:#ae81ff">Terminating</span> -</span></span></code></pre></div><p>Notice the inclusion of the finalizers field in the above JSON. Some namespaces have a finalizer defined under spec.</p> -<p>A finalizer is a special metadata key that tells Kubernetes to wait until a specific condition is met before it fully deletes a resource. Much like a finalizer in the .NET framework (does Java have those too? 😀 )</p> -<p>So when you run a command like <code>kubectl delete namespace &lt;namespace&gt;</code>, Kubernetes checks for a finalizer in the <code>metadata.finalizers</code> field. If the resource defined in the finalizer cannot be deleted, then the namespace is not deleted either. This puts the namespace into a perpetual terminating state and is never actually deleted.</p> -<p>When an object has been terminating for an excessive time, check its finalizers by inspecting the <code>metadata.finalizers</code> field in its YAML.</p> -<p>So we now know what the problem is. How can we solve it? Well, it’s actually quite simple. If you are using bash, use this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> -</span></span><span style="display:flex;"><span>namespaces<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>kubectl get ns --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Terminating -o jsonpath<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;{range .items[*]}{.metadata.name}{&#34;\n&#34;}{end}&#39;</span><span style="color:#66d9ef">)</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -z <span style="color:#e6db74">&#34;</span>$namespaces<span style="color:#e6db74">&#34;</span><span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">&#34;No namespaces to delete.&#34;</span> -</span></span><span style="display:flex;"><span> exit -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> namespace in $namespaces -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">do</span> -</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">&#34;[Removing Namespace]: </span>$namespace<span style="color:#e6db74">&#34;</span> -</span></span><span style="display:flex;"><span> kubectl get namespace $namespace -o json | tr -d <span style="color:#e6db74">&#34;\n&#34;</span> | sed <span style="color:#e6db74">&#34;s/\&#34;finalizers\&#34;: \[[^]]\+\]/\&#34;finalizers\&#34;: []/&#34;</span> | kubectl replace --raw /api/v1/namespaces/$namespace/finalize -f - &gt; /dev/null 2&gt;&amp;<span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">done</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span> -</span></span></code></pre></div><p><a href="https://gist.github.com/rnemeth90/e83bb4c8808f0d28412cb40edb2487d3">Delete Terminating Kubernetes Namespaces with Bash (github.com)</a></p> -<p>It will search for any namespace that is stuck in the terminating state and forcefully remove it by removing the finalizers field and then using <code> kubectl replace</code> to commit the change back to the Kube API.</p> -<p>If you prefer Powershell, you can use this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$terminatingNamespaces = kubectl get ns --field-selector=status.phase==Terminating -o jsonpath=<span style="color:#e6db74">&#34;{range .items[*]}{.metadata.name}{&#39;\n&#39;}{end}&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($ns <span style="color:#66d9ef">in</span> $terminatingNamespaces) { -</span></span><span style="display:flex;"><span> Write-Verbose <span style="color:#e6db74">&#39;[FOUND]: Forcefully removing $ns&#39;</span> -</span></span><span style="display:flex;"><span> $jsonObj = kubectl get namespace $ns -o json | ConvertFrom-Json | foreach-object { $_.spec.finalizers = @(); $_ } | -</span></span><span style="display:flex;"><span> convertto-json | kubectl replace --raw /api/v1/namespaces/$namespace/finalize <span style="color:#f92672">-f</span> - -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><a href="https://gist.github.com/rnemeth90/19d7de622a5009c1cf908c5d4deb5358">Delete Terminating Kubernetes Namespaces with Powershell (github.com)</a></p> -<p>It does the same thing as the bash script, just in more of a Window-zy way.</p> -<p>It’s that simple. I hope this was helpful. If you have any questions, comments, or concerns, please feel free to reach out.</p> - + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state. A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. - Kubernetes Storage Simplified - https://rnemeth90.github.io/posts/2022-03-01-kubernetes-storage-simplified/ + http://localhost:1313/posts/2022-03-01-kubernetes-storage-simplified/ Tue, 01 Mar 2022 08:37:58 +0000 - - https://rnemeth90.github.io/posts/2022-03-01-kubernetes-storage-simplified/ - <p>In this blog post, we will attempt to explain the current storage options that exist in Kubernetes. If you are new to Kubernetes, learning about its capabilities of managing the application state can be a daunting task.</p> -<p>Container images are built-in layers, with the runtime layer being writable. However, any files on this writable layer are only available for the container’s lifetime. We can mount a volume to a directory inside the container to have persistent data.</p> -<p>Kubernetes storage uses the concepts of volumes. Ephemeral volumes are called volumes and only last the lifetime of a pod, and “persistent volumes” are used for long-term storage. A typical use case for Ephemeral volumes is storing logs that are not sent to stdout.</p> -<p>Mounting a persistent volume inside a container allows you to persist the state of your application long after the container is terminated. Persistent volumes can also take advantage of the typical storage idiosyncrasies such as backup, compression, and encryption.</p> -<h2 id="persistent-volumes" >Persistent Volumes -<span> - <a href="#persistent-volumes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Kubernetes has several types of persistent volumes. At its core, a persistent volume is simply a directory mounted inside a pod. How that volume is created, the configuration options and the medium that backs it are all determined by the type of volume created.</p> -<p>There are several types of volumes available, too many to list here. You may commonly see some volume types: NFS, iSCSI, hostpath, and local. If your Kubernetes cluster exists in a cloud environment such as Azure or AWS, other volume types are available to you (azureDisk, azureFile, and awsElasticBlockStore, respectively). A complete list of types can be found here:</p> -<p><a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes">https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes</a></p> -<p>Creating a persistent volume is generally a simple task. The first step is determining the type of volume to create. In this post, we will cover creating a local volume. A local volume represents a disk, partition, or directory shared from a node. Local volumes are subject to the availability of the underlying node, meaning that if the node is offline, the volume is also offline and will not be accessible by any pod. Because of this, local volumes should not be used in production.</p> -<p>A persistent volume can only be created using a declarative approach. To create a persistent local volume, use the following YAML definition:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolume</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">example-pv</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">capacity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMode</span>: <span style="color:#ae81ff">Filesystem</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteOnce</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeReclaimPolicy</span>: <span style="color:#ae81ff">Delete</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">local-storage</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">local</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># the path to the volume or directory on the node</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/mnt/disks/ssd1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeAffinity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">required</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeSelectorTerms</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">matchExpressions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">key</span>: <span style="color:#ae81ff">kubernetes.io/hostname</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">operator</span>: <span style="color:#ae81ff">In</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">values</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># name of the node sharing the volume</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">node01</span> -</span></span></code></pre></div><p>When creating a persistent volume of this type, you must specify a node affinity. This ensures that the Kubernetes scheduler schedules any pods requesting access to this volume on the correct node. For example, any pod requesting access to the persistent volume named ‘example-PV will only be scheduled on the node ‘node01’.</p> -<p>Let’s dive into this persistent volume spec a bit more:</p> -<p>You can change the capacity of the persistent volume by updating:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">capacity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span></code></pre></div><p>The accessModes will be determined by the storage provider being used. There are generally 3 access modes available: ReadWriteOnce, ReadWriteMany, and ReadOnlyMany.</p> -<ul> -<li>ReadWriteOnce – The volume can be mounted as read-write by a single node</li> -<li>ReadWriteMany – The volume can be mounted as read-write by many nodes</li> -<li>ReadOnlyMany – The volume can be mounted as read-only by many nodes</li> -</ul> -<p>The “persistentVolumeReclaim” policy determines what happens to a persistent volume when it is no longer mounted by any pods (i.e., there are no claims to it, more on this later). There are three options available for the reclaim policy:</p> -<ul> -<li>Retain – The persistent volume is kept as-is. It must be manually removed when no longer needed.</li> -<li>Recycle – The persistent volume is scrubbed and can be re-used by other pods</li> -<li>Delete – The persistent volume is deleted.</li> -</ul> -<p>Currently, only NFS and hostPath volumes support recycling. Cloud storage providers (Azure, AWS, and GCE) support deletion.</p> -<p>The other aspects of this spec are unique to the volume being used. Since we are using a local volume here, we must specify the path to the directory or volume on the host and the host which is sharing the directory or volume:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span> <span style="color:#f92672">local</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># the path to the volume or directory on the node</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/mnt/disks/ssd1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeAffinity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">required</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeSelectorTerms</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">matchExpressions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">key</span>: <span style="color:#ae81ff">kubernetes.io/hostname</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">operator</span>: <span style="color:#ae81ff">In</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">values</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># name of the node sharing the volume</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">node01</span> -</span></span></code></pre></div><h2 id="ephemeral-volumes" >Ephemeral Volumes -<span> - <a href="#ephemeral-volumes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Note: The Kubernetes documentation recognizes configMaps and Secrets as ephemeral volumes. However, in this article, we will only discuss ephemeral volumes used for data storage (emptyDir volumes).</p> -<p>Ephemeral volumes are defined within the context of a pod. This means that you cannot create an ephemeral volume on its own. Instead, define the ephemeral volume in the pod or a deployment spec.</p> -<p>Ephemeral volumes are useful in a few scenarios:</p> -<ol> -<li>You want to share data between multiple containers in a pod</li> -<li>You want to cache temporary information such as log files</li> -<li>You need scratch space to store data before it is processed by another container or pod</li> -</ol> -<p>If one of the containers in the pod happens to restart, data on the ephemeral volume will still exist; as long as one of the containers is mounting, it stays online. In other words, if a pod mounting the ephemeral volume is removed from a node, data on the ephemeral volume is lost. However, if a pod crashes, the data on the volume remains intact.</p> -<p>As stated previously, creating an ephemeral volume is done as part of the pod or deployment template:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/cache</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">emptyDir</span>: {} -</span></span></code></pre></div><p>If the template, you add a volume of type ’emptyDir’ in the ‘volumes’ spec and name it. You can mount this volume in any container in the pod. The volume does not have to be mounted to the same directory in each container.</p> -<h2 id="persistent-volume-claims" >Persistent Volume Claims -<span> - <a href="#persistent-volume-claims"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>A persistentVolumeClaim (often referred to as a ‘PVC’) is used by a pod to create a ‘claim’ on storage. Using a PVC, a pod can mount multiple persistent volumes simultaneously to any directory in the pod.</p> -<p>PersistentVolumeClaim’s are a Kubernetes primitive that can be deployed from a manifest:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fast-storage-pvc</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMode</span>: <span style="color:#ae81ff">Filesystem</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">8Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">fast</span> -</span></span></code></pre></div><p>Most of the options in the manifest above seem pretty obvious. The volumeMode specifies whether to consume the persistent volume as a FileSystem or block device. The resources section helps specify the amount of storage you require (8Gi in this example). We will cover the storageClassName in the next section. Finally, the accessModes are identical to those described above in the Persistent Volumes section.</p> -<p>Pods access a volume by using the persistentVolumeClaim as volume. Claims must exist in the same namespace as the pod using the claim. The controller finds the claim in the pods’ namespace and uses it to find a persistent volume capable of backing the claim. The volume is then mounted on the host and attached to the pod.</p> -<p>To create a pod that utilizes a PVC, use the following yaml definition:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/mnt/share</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span></code></pre></div><h2 id="storage-classes" >Storage Classes -<span> - <a href="#storage-classes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>In this article, we will only be referencing Kubernetes storage classes with respect to dynamic provisioners. If you would like to learn more, please reference the Kubernetes docs:</p> -<p><a href="https://bit.ly/3ruJD2A">https://bit.ly/3ruJD2A</a></p> -<p>Storage Classes have many uses. Kubernetes is unopinionated about what a storage class represents. They can be used to represent different characteristics of storage (performance, compression method, file system modes, etc.). Storage Classes can also be used to provision persistent volumes dynamically, which will be the focus of this article.</p> -<p>Storage classes are often packaged with CSI drivers. Each StorageClass contains the fields “provisioner”, “parameters”, and “reclaimPolicy”. The provisioner field is used to determine what CSI driver is used for provisioning volumes.</p> -<p>This is an example of the storage class packaged with the AzureFiles CSI driver:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">StorageClass</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">storage.k8s.io/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azurefileshare</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">provisioner</span>: <span style="color:#ae81ff">file.csi.azure.com</span> <span style="color:#75715e"># replace with &#34;kubernetes.io/azure-file&#34; if aks version is less than 1.21</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">mountOptions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">dir_mode=0777</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">file_mode=0777</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">uid=0</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">gid=0</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">mfsymlinks</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">cache=strict</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">actimeo=30</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">parameters</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">skuName</span>: <span style="color:#ae81ff">Standard_LRS</span> -</span></span></code></pre></div><p>You can see in the above manifest that the provisioner is set to ‘file.csi.azure.com.’ When a pod uses a PVC in its manifest that references this storage class, the provisioner will dynamically manage the underlying storage.</p> -<p>The name of the storageClass is referenced in the persistentVolumeClaim:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">8Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">azurefileshare</span> -</span></span></code></pre></div><p>You could then reference this PVC in a pod:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/mnt/share</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span></code></pre></div><p>That concludes this article. I know that is a lot of information! As always, if you have any questions or comments, please reach out.</p> - + http://localhost:1313/posts/2022-03-01-kubernetes-storage-simplified/ + In this blog post, we will attempt to explain the current storage options that exist in Kubernetes. If you are new to Kubernetes, learning about its capabilities of managing the application state can be a daunting task. Container images are built-in layers, with the runtime layer being writable. However, any files on this writable layer are only available for the container’s lifetime. We can mount a volume to a directory inside the container to have persistent data. - Kubernetes Pod Eviction - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ Sat, 05 Feb 2022 23:49:16 +0000 - - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ - <p>In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation.</p> -<h2 id="what-is-pod-eviction" >What is Pod Eviction? -<span> - <a href="#what-is-pod-eviction"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. The most common of which is resource starvation on a node. This is referred to as “node-pressure eviction.”</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>NAME READY STATUS RESTARTS AGE -</span></span><span style="display:flex;"><span>nginx 0/1 Evicted <span style="color:#ae81ff">0</span> 10s -</span></span></code></pre></div><h2 id="eviction-process" >Eviction Process -<span> - <a href="#eviction-process"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The kubelet process running on the node monitors resources such as CPU, memory, disk space, inodes, etc. When one of these resources reaches a certain consumption level, the kubelet will first attempt to clean up resources by deleting non-running pods and images (in the case of storage starvation). The kubelet will then fail one or more pods on the node to reclaim resources. The class of the pod determines the order in which it does this.</p> -<p><strong>Pod Classes</strong></p> -<ul> -<li>Guaranteed: Pods that have requests and limits configured for both CPU and memory</li> -<li>Burstable: Pods with a resource request configured for memory or CPU</li> -<li>Best Effort: Pods without any requests or limits</li> -</ul> -<p>The kubelet will first evict any “best-effort” pods. If this is not enough, the kubelet will evict any “burstable” pods. Pods within the “guaranteed” class are theoretically safe from eviction.</p> -<p>During a node-pressure eviction, the kubelet sets the PodPhase for the selected pods to “Failed.” This causes the pods to terminate. If a daemonSet or replicaSet manages the pod, the Kubernetes controller-manager will create new pods on another node.</p> -<h2 id="recovery" >Recovery -<span> - <a href="#recovery"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Node-pressure eviction is almost always avoidable. We can prevent this type of issue by ensuring that we properly size our clusters and create resource limits for pods.</p> -<p><strong>Resource</strong> <strong>Requests and Limits:</strong></p> -<ul> -<li>Requests: The minimum amount of resources (CPU/memory) that a container needs to start.</li> -<li>Limits: The maximum amount of resources that a container is allowed to use.</li> -</ul> -<p>Pod resources and requests can be defined in a pod spec or deployment spec. Below is an example of a pod spec with resource requests and limits defined:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">frontend</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">nginx</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;64Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;250m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">limits</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;128Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;500m&#34;</span> -</span></span></code></pre></div><p>You will often need to clean up evicted pods manually. If you find that your cluster has a large amount of evicted pods, you can clean them up with the following kubectl commands:</p> -<p><strong>To see all failed pods in the cluster:</strong></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl get pod --all-namespaces --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Failed -</span></span></code></pre></div><p><strong>To remove all failed pods in the cluster:</strong></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl delete pod --all-namespaces --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Failed -</span></span></code></pre></div><p>I hope this article has been helpful. Please reach out if you have any questions or comments! Also, if you would like to learn more, take a look at the official Kubernetes docs:</p> -<p><a href="https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/">https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/</a></p> - + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ + In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation. What is Pod Eviction? Link to heading Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. - Azure Kubernetes sFTP Solution - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ + http://localhost:1313/posts/2022-01-16-azure-kubernetes-sftp-solution/ Sun, 16 Jan 2022 07:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ - <p>In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault.</p> -<p>Here is the link to my Github account where you can download the code mentioned in this article:</p> -<p><a href="https://github.com/rnemeth90/kubernetes-sftp">https://github.com/rnemeth90/kubernetes-sftp</a></p> -<p>We will work through the following steps in this article:</p> -<ol> -<li>Deploy the AzureFile CSI driver to the AKS cluster</li> -<li>Create a configMap that our initContainer will</li> -<li>Deploy a persistent volume claim that an Azure File share will back</li> -<li>Deploy a replicaSet consisting of our initContainer and application container</li> -<li>Deploy a service to serve traffic</li> -</ol> -<p>First, you will need to deploy the Azure Files CSI driver to your AKS cluster. AKS uses this daemon set to dynamically provision/destroy Azure NFSv4 File Shares. The Azure Files CSI driver creates a storage account in the node pool resource group, in which it will then provision the file share.</p> -<p>Deploying the Azure Files CSI driver is a simple task. You will need to run this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/install-driver.sh | bash -s master -- -</span></span></code></pre></div><p>You can use the following commands to verify that the daemon set has exists:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl -n kube-system get pod -o wide --watch -l app<span style="color:#f92672">=</span>csi-azurefile-controller -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>kubectl -n kube-system get pod -o wide --watch -l app<span style="color:#f92672">=</span>csi-azurefile-node -</span></span></code></pre></div><figure class="wp-block-coblocks-gallery-masonry masonry-grid has-border-radius-10 has-medium-gutter"><figure class="wp-block-image size-large masonry-brick">[![Image gallery image](https://rnemeth90.github.io/wp-content/uploads/2022/01/image-1-1024x434.png)](https://rnemeth90.github.io/wp-content/uploads/2022/01/image-1.png)</figure></figure>Next, you need to create a storage class by deploying this yaml file: -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl create -f https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/example/storageclass-azurefile-nfs.yaml -</span></span></code></pre></div><p>Read more about the AzureFiles CSI driver at the following Github link:</p> -<p><a href="https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/install-driver-on-aks.md">https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/install-driver-on-aks.md</a></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ConfigMap</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">creationTimestamp</span>: <span style="color:#66d9ef">null</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">testcm</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">init.sh</span>: |-<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> #!/bin/bash -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> CONF_FILE=&#34;/etc/sftp/users.conf&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> KEYVAULT=&#34;Insert name of Key Vault&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_ID=&#34;Insert service principal Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_PASSWORD=&#34;Insert service principal password&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_TENANT_ID=&#34;Insert Az AAD Tenant Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SUBSCRIPTION_ID=&#34;Insert Az Subscription Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az login --service-principal --username &#34;${AZ_SPN_ID}&#34; --password &#34;${AZ_SPN_PASSWORD}&#34; --tenant &#34;${AZ_SPN_TENANT_ID}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az account set --subscription &#34;${AZ_SUBSCRIPTION_ID}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETS+=($(az keyvault secret list --vault-name $KEYVAULT --query &#34;[].id&#34; -o tsv)) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> chmod 755 /home -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [[ -e $CONF_FILE ]]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> rm -rf &#34;${CONF_FILE}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> touch $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> else -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> touch $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> for SECRET in &#34;${SECRETS[@]}&#34;; do -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETNAME=$(basename $SECRET | tr -d &#39;\r&#39;) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETVALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $SECRETNAME --query &#39;value&#39; | tr -d &#39;&#34;&#39; | tr -d &#39;\r&#39;) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;$SECRETNAME:$SECRETVALUE:::upload&#34; &gt;&gt; $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> done -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [[ ! -s $CONF_FILE ]]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;** ERROR: user.conf is empty&#34; 1&gt;&amp;2 -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> exit 1 -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi</span> -</span></span></code></pre></div><p>The initContainer will use this configMap to read secrets from an Azure Key Vault and then write the secrets to the users.conf file. The users.conf file contains user account information. In the Key Vault, the secret name should be the username and the secret value should be the password. This Key Vault must exist and contain the secrets prior to deploying this solution.</p> -<p>When I deployed this solution in my environment, I used an Azure DevOps pipeline to create/manage the Key Vault with Terraform and then deploy the secrets using an inline Powershell script. However, this is beyond the scope of this article, and I will not be covering it here. You will also need to create a Service Principal in your AAD tenant and grant it access to the Key Vault. The Service Principal needs to have at least read access to the Key Vault.</p> -<p>Before deploying the configMap, you need to fill in values for these variables:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span> KEYVAULT<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert name of Key Vault&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert service principal Id&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_PASSWORD<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert service principal password&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_TENANT_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert Az AAD Tenant Id&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SUBSCRIPTION_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert Az Subscription Id&#34;</span> -</span></span></code></pre></div><p>These values pertain to the service principal with read access to the Key Vault. After filling out these variables, you can deploy the configMap using kubectl.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl create -f configmap.yaml -</span></span></code></pre></div><p>You can deploy the PVC using this yaml file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">azurefile-csi-nfs</span> -</span></span></code></pre></div><p>When creating the persistent volume claim for the deployment, you specify azurefile-csi-nfs as the StorageClass. This will create an NFSv4 share in a premium storage account. The reclaim policy of the storage class ensures that the file share is deleted when the associated Persistent Volume is deleted. Change the reclaim policy to “Retain” if you want the file shares to persist after deleting the PV. Furthermore, the storage class enables the file share to be expandable by modifying the storage request size on the PVC.</p> -<p>After deploying the PVC, you can verify its existence by running:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl get pvc -</span></span></code></pre></div><p>You should see output similar to the following (the manifest for the replicaSet is by far the most complicated of all the code referenced here):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Deployment</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">matchLabels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">strategy</span>: {} -</span></span><span style="display:flex;"><span> <span style="color:#f92672">template</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initContainer</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">chmodder</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">mcr.microsoft.com/azure-cli</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">command</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">/bin/sh</span> -</span></span><span style="display:flex;"><span> - -<span style="color:#ae81ff">c</span> -</span></span><span style="display:flex;"><span> - <span style="color:#e6db74">&#34;/scripts/init.sh&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/scripts</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">docker.io/atmoz/sftp:alpine</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">imagePullPolicy</span>: <span style="color:#ae81ff">IfNotPresent</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;64Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;250m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">limits</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;128Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;500m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">livenessProbe</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tcpSocket</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initialDelaySeconds</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">timeoutSeconds</span>: <span style="color:#ae81ff">5</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">periodSeconds</span>: <span style="color:#ae81ff">10</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">failureThreshold</span>: <span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readinessProbe</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tcpSocket</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initialDelaySeconds</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">timeoutSeconds</span>: <span style="color:#ae81ff">5</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">periodSeconds</span>: <span style="color:#ae81ff">10</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">failureThreshold</span>: <span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/home</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/etc/sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">dnsPolicy</span>: <span style="color:#ae81ff">ClusterFirst</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">restartPolicy</span>: <span style="color:#ae81ff">Never</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">configMap</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">emptyDir</span>: {} -</span></span></code></pre></div><p>You may need to change the CPU/memory requests and limits. These values worked for me, but your results may vary. You can also add/change the labels as you see fit.</p> -<p>This will handle routing traffic to our pods.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Service</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp-service</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">LoadBalancer</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">ports</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">protocol</span>: <span style="color:#ae81ff">TCP</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">targetPort</span>: <span style="color:#ae81ff">22</span> -</span></span></code></pre></div><p>Users will be connected in a round-robin fashion to the pods. This manifest will create a service of type LoadBalancer. Which will in turn create a new public Azure Load Balancer in the resource group that contains your Azure Kubernetes Service cluster if one does not already exist. If you already have a public load balancer, a new frontend IP address will be added.</p> -<p>That’s all for now. Please feel free to contact me if you have any questions.</p> - + http://localhost:1313/posts/2022-01-16-azure-kubernetes-sftp-solution/ + In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault. Here is the link to my Github account where you can download the code mentioned in this article: https://github.com/rnemeth90/kubernetes-sftp We will work through the following steps in this article: - diff --git a/public/categories/azure-kubernetes-service/page/1/index.html b/public/categories/azure-kubernetes-service/page/1/index.html index e52df861..7a211d3e 100644 --- a/public/categories/azure-kubernetes-service/page/1/index.html +++ b/public/categories/azure-kubernetes-service/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/azure-kubernetes-service/ - + http://localhost:1313/categories/azure-kubernetes-service/ + - + diff --git a/public/categories/azure/index.html b/public/categories/azure/index.html index 10bf7f2b..ececda84 100644 --- a/public/categories/azure/index.html +++ b/public/categories/azure/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: Azure · GeekyRyan + - - -Azure - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,285 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Category: Azure

    - - - -
    -
    -
    -

    Backup Synology NAS to Azure Storage

    -
    -
    +
    +
    + © -
    - I’m not really a fan of photography. I don’t particularly enjoy the intracies of tuning a high-end DSLR camera. Nor am I a fan of being out in nature to photograph a fall sunrise (though, that does sound peaceful). However, I do take a lot of pictures with my phone (currently, a Pixel 6). Moreso now that I am a new father. I am protective of these photos. So much that I sync them automatically from my phone to two cloud storage providers. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-12-25-synology-backup-to-cloud/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - - + + diff --git a/public/categories/azure/index.xml b/public/categories/azure/index.xml index ded131f5..bd2ecd53 100644 --- a/public/categories/azure/index.xml +++ b/public/categories/azure/index.xml @@ -2,48 +2,18 @@ Azure on GeekyRyan - https://rnemeth90.github.io/categories/azure/ - GeekyRyan (Azure) - Hugo -- gohugo.io - en-us + http://localhost:1313/categories/azure/ + Recent content in Azure on GeekyRyan + Hugo + en Tue, 27 Dec 2022 00:00:00 +0000 - - - - + Backup Synology NAS to Azure Storage - https://rnemeth90.github.io/posts/2022-12-25-synology-backup-to-cloud/ + http://localhost:1313/posts/2022-12-25-synology-backup-to-cloud/ Tue, 27 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-25-synology-backup-to-cloud/ - <p>I&rsquo;m not really a fan of photography. I don&rsquo;t particularly enjoy the intracies of tuning a high-end DSLR camera. Nor am I a fan of being out in nature to photograph a fall sunrise (though, that does sound peaceful). However, I do take a lot of pictures with my phone (currently, a Pixel 6). Moreso now that I am a new father. I am protective of these photos. So much that I sync them automatically from my phone to two cloud storage providers. I thought the other day, how painful it would be for either of these cloud storage providers to go offline. Though unlikely, anything is possible, right?</p> -<p>So, like any good engineer, I started looking for a solution for this concern. I have 2 Synology NAS devices here at my home. Calling a Synology a NAS is almost an insult. They are much more than that. Though they specialize in storage, they provide a plethora of apps that extend the functionality of the device. A Synology device can provide storage, email, DNS, media, etc. services though OEM and third-party apps. A single device can also link up with other devices to form a highly-available mesh of Synology services. Pretty neat for just a little black desktop box! Anyway, I&rsquo;m not a Synology salesman, so let&rsquo;s get back on track&hellip;</p> -<p>I wanted to be able to have a local copy of all of my photos (and other files) that are currently synced to the cloud. I then wanted to backup this local copy to another remote location (something like a 3-2-1 backup architecture, but not really&hellip;). Synology provides an app called Cloud Sync that can be used to sync files from a cloud storage provider like Google Photos/Drive or Microsoft OneDrive to a local device. They also provide another app called Hyper Backup that can be used to backup local files to remote storage, like an Azure Storage Account or Amazon S3 Bucket. By now, you probably get where this is going.</p> -<p>I&rsquo;m going to configure Cloud Sync to pull files down to my Synology and then use Hyper Backup to push a weekly backup to Azure Blob Storage. Let&rsquo;s dive in! -If you&rsquo;re following along, you&rsquo;ll need to install both of these apps. They are available via One-Click install in the Synology Package Center, so I won&rsquo;t cover the installation process. The setup is extremely simple as well, but I&rsquo;ll go over it just because.</p> -<p>We&rsquo;ll first setup Cloud Sync. Open Cloud Sync and click the &lsquo;+&rsquo; symbol to add a new account.</p> -<p>For my purposes, I&rsquo;m going to choose Microsoft OneDrive:</p> -<p><a href="https://rnemeth90.github.io/images/synology-cloud-sync-01.png"><img src="https://rnemeth90.github.io/images/synology-cloud-sync-01.png" alt=""></a></p> -<p>When prompted to authenticate, login to your OneDrive account. Then, configure the sync settings. You can create a name for the connection, add a local path in which to sync your files to, choose which remote folders/files to sync, the sync direction, a schedule, etc.</p> -<p><a href="https://rnemeth90.github.io/images/synology-cloud-sync-02.png"><img src="https://rnemeth90.github.io/images/synology-cloud-sync-02.png" alt=""></a></p> -<p>Click Next, and then finish the wizard. Simple.</p> -<p>Depending on the amount of files you have, you&rsquo;ll need to allow some time for your files to sync.</p> -<p>Now, we&rsquo;ll setup Hyper Backup to backup the files you sync&rsquo;d locally to remote storage. As stated previously, I&rsquo;ll be backing up my files to Azure Blob Storage. I have already created the Storage Account in Azure, and will not be covering that in this article.</p> -<p>Open Hyper Backup and click the &lsquo;+&rsquo; symbol in the lower left corner, and then click &lsquo;Data Backup Task&rsquo;. Then, choose &lsquo;Microsoft Azure&rsquo;:</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-01.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-01.png" alt=""></a> -<a href="https://rnemeth90.github.io/images/synology-hyper-backup-02.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-02.png" alt=""></a></p> -<p>On the next page, enter in your Storage Account info and then click Next. You can then choose which local folders on your Synology to backup:</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-03.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-03.png" alt=""></a></p> -<p>Click next and choose to backup application settings:</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-04.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-04.png" alt=""></a></p> -<p>On this page, we can configure the backup settings. Name the task, and configure your notification settings, schedule, compression, and encryption.</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-05.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-05.png" alt=""></a></p> -<p>On the last page, we configure our backup rotation settings. I am going to keep 31 days of backups, starting from the oldest backup. This means that at any given time I will have 31 days worth of backups in the storage account.</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-06.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-06.png" alt=""></a></p> -<p>That&rsquo;s all for configuring the backups! Very simple. Depending on how much data you have and your ISP, it may take a while to backup your files. If you configured notifications, you should receive a notification once the job is complete.</p> - + http://localhost:1313/posts/2022-12-25-synology-backup-to-cloud/ + I&rsquo;m not really a fan of photography. I don&rsquo;t particularly enjoy the intracies of tuning a high-end DSLR camera. Nor am I a fan of being out in nature to photograph a fall sunrise (though, that does sound peaceful). However, I do take a lot of pictures with my phone (currently, a Pixel 6). Moreso now that I am a new father. I am protective of these photos. So much that I sync them automatically from my phone to two cloud storage providers. - diff --git a/public/categories/azure/page/1/index.html b/public/categories/azure/page/1/index.html index 7259a45e..a3d43a22 100644 --- a/public/categories/azure/page/1/index.html +++ b/public/categories/azure/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/azure/ - + http://localhost:1313/categories/azure/ + - + diff --git a/public/categories/c#/index.html b/public/categories/c#/index.html index a0da1016..e631b09b 100644 --- a/public/categories/c#/index.html +++ b/public/categories/c#/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: C# · GeekyRyan + - - -c# - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,306 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Category: c#

    - - - -
    -
    -
    -

    EF Core &#8211; Unable to create an object of type DbContext

    -
    -
    +
    +
    + © -
    - This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it! -When running EF Core migrations in a solution, you may come across this error: -There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio. -To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - - + + diff --git a/public/categories/c#/index.xml b/public/categories/c#/index.xml index 8c383775..ffbd8816 100644 --- a/public/categories/c#/index.xml +++ b/public/categories/c#/index.xml @@ -1,32 +1,19 @@ - c# on GeekyRyan - https://rnemeth90.github.io/categories/c#/ - GeekyRyan (c#) - Hugo -- gohugo.io - en-us + C# on GeekyRyan + http://localhost:1313/categories/c%23/ + Recent content in C# on GeekyRyan + Hugo + en Sun, 12 Jun 2022 13:58:52 +0000 - - - - + EF Core &#8211; Unable to create an object of type DbContext - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ Sun, 12 Jun 2022 13:58:52 +0000 - - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ - <p>This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it!</p> -<p>When running EF Core migrations in a solution, you may come across this error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-1-1024x142.png"></a></p> -<p>There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio.</p> -<p>To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-2.png"></a></p> -<p>If you are using clean architecture, or some other architecture that has your startup context and your dbContext in different projects, you will need to set your startup project to your runtime, and the ‘Default Project’ in the package manager console to the project containing your dbContext.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-3-1024x493.png"></a></p> - + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it! When running EF Core migrations in a solution, you may come across this error: There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio. To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’. - diff --git a/public/categories/c#/page/1/index.html b/public/categories/c#/page/1/index.html index 641a4c0a..ec04011a 100644 --- a/public/categories/c#/page/1/index.html +++ b/public/categories/c#/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/c#/ - + http://localhost:1313/categories/c%23/ + - + diff --git a/public/categories/ci/cd/index.html b/public/categories/ci/cd/index.html index 66be2a78..36b4e1a4 100644 --- a/public/categories/ci/cd/index.html +++ b/public/categories/ci/cd/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: CI/CD · GeekyRyan + - - -CI/CD - GeekyRyan - - - - - - - - - - + - - + + + - - + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,357 +79,161 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    -
    -
    - -

    Category: CI/CD

    - + 2022-02-19 + Accessing Secrets Securely in Azure DevOps Pipelines + +
  • + 2022-01-14 + Continuous Deployment Models +
  • -
    -
    -
    -

    Accessing Secrets Securely in Azure DevOps Pipelines

    -
    - -
    + + - -
    - This post will cover a secure method for accessing secrets in Azure DevOps pipelines. -Why Azure Key Vault? Azure Key Vault is an Azure cloud service used to securely store secrets, keys, and certificates. A secret can be any string of characters, such as API keys, passwords, URLs, etc. Azure Key Vault encrypts data at rest and in transit using HTTPS. Depending on the type of Key Vault you are using, data at rest is encrypted using software encryption (AES 256) or HSM-backed keys. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Continuous Deployment Models

    -
    -
    +
    +
    + © -
    - When deploying new software releases to servers or (insert -as-a-service> here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments. -Blue/Green Deployments Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. Instead, it gets deployed to another set of servers (blue) first. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - +
    +
    -
    - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - - + + diff --git a/public/categories/ci/cd/index.xml b/public/categories/ci/cd/index.xml index 7375240a..232891d8 100644 --- a/public/categories/ci/cd/index.xml +++ b/public/categories/ci/cd/index.xml @@ -2,162 +2,25 @@ CI/CD on GeekyRyan - https://rnemeth90.github.io/categories/ci/cd/ - GeekyRyan (CI/CD) - Hugo -- gohugo.io - en-us - - - - + http://localhost:1313/categories/ci/cd/ + Recent content in CI/CD on GeekyRyan + Hugo + en + Sat, 19 Feb 2022 16:02:50 +0000 + Accessing Secrets Securely in Azure DevOps Pipelines - https://rnemeth90.github.io/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ + http://localhost:1313/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ Sat, 19 Feb 2022 16:02:50 +0000 - - https://rnemeth90.github.io/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ - <p>This post will cover a secure method for accessing secrets in Azure DevOps pipelines.</p> -<h2 id="why-azure-key-vault" >Why Azure Key Vault? -<span> - <a href="#why-azure-key-vault"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Azure Key Vault is an Azure cloud service used to securely store secrets, keys, and certificates. A secret can be any string of characters, such as API keys, passwords, URLs, etc. Azure Key Vault encrypts data at rest and in transit using HTTPS. Depending on the type of Key Vault you are using, data at rest is encrypted using software encryption (AES 256) or HSM-backed keys.</p> -<p>Azure Key Vault also gives us the ability to control access to secrets, keys, and certificates using native Key Vault access policies or the newer option of Azure IAM (RBAC) integration.</p> -<h2 id="what-are-variable-groups" >What are Variable Groups? -<span> - <a href="#what-are-variable-groups"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>It’s all in the name. Variable groups are simply a method of grouping Azure DevOps pipeline variables. If you created a release for an application named MyAwesomeApp, you could create a variable group named myawesomeapp-var-group that could then store all of the variables you reference in the release. It’s simply a method of organizing variables.</p> -<p>You apply permissions to variable groups so that only certain people and pipelines/releases are able to use them.</p> -<p>You can read more here about variable groups and their usage:</p> -<p><a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/library/variable-groups?view=azure-devops&amp;tabs=yaml#use-a-variable-group">https://docs.microsoft.com/en-us/azure/devops/pipelines/library/variable-groups?view=azure-devops&amp;tabs=yaml#use-a-variable-group</a></p> -<h2 id="creating-a-key-vault-and-adding-secrets" >Creating a Key Vault and Adding Secrets -<span> - <a href="#creating-a-key-vault-and-adding-secrets"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p><strong>If you already have a Key Vault, skip this section.</strong></p> -<p>In this post, we will create a Key Vault using the AzureCLI. To create the Vault and a secret, run these commands:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># Create a resource group</span> -</span></span><span style="display:flex;"><span>az group create --location &lt;location&gt; --name &lt;resource-group-name&gt; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Create a KeyVault</span> -</span></span><span style="display:flex;"><span>az keyvault create --name &lt;keyvault-name&gt; --resource-group &lt;resource-group-name&gt; --enable-soft-delete -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Create some secrets in the Key Vault</span> -</span></span><span style="display:flex;"><span>az keyvault secret set --name username --vault-name &lt;keyvault-name&gt; --value &lt;username&gt; -</span></span><span style="display:flex;"><span>az keyvault secret set --name password --vault-name &lt;keyvault-name&gt; --value &lt;password&gt; -</span></span><span style="display:flex;"><span>az keyvault secret set --name tenantId--vault-name &lt;keyvault-name&gt; --value &lt;tenant id&gt; -</span></span></code></pre></div><p>You will need to update the location and resource group name with whatever values you want. You will also need to update the username, password, and your Azure AD tenant ID. The username you choose will need read access to your subscription.</p> -<h2 id="creating-a-variable-group" >Creating a Variable Group -<span> - <a href="#creating-a-variable-group"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Now we’ll create the variable group in Azure DevOps.</p> -<p>Go to your Azure DevOps project &gt; Pipelines &gt; Library and click “+ Variable Group”:</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image.png"></a></p> -<p>Give your variable group a name. Then toggle the switch “Link secrets from an Azure key vault as variables”. Select your Azure Subscription (you may need to authorize DevOps access to the subscription, and then select the Key Vault.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-1.png"></a></p> -<p>Now we can add the secrets from the Key Vault to the variable group. Under “Variables”, click the “+ Add” button. Select the checkbox next to any secrets you want to add to the variable group, and then click “Ok”.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-7.png"></a></p> -<p>Finally, click the “Save” button. You now have a variable group with secrets linked to a Key Vault. Notice the name of the secret is the only thing visible from the variable group. If you were to update the secret value in the Key Vault, Azure DevOps would automatically pick up the new value.</p> -<h2 id="use-the-variable-group-in-a-pipeline" >Use the Variable Group in a Pipeline -<span> - <a href="#use-the-variable-group-in-a-pipeline"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Now that we have our variable group in place, let’s use it in a pipeline. In Azure DevOps, go to Pipelines and click “New pipeline”.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-8-1024x596.png"></a></p> -<p>Choose “Azure Repos Git” &gt; “&lt; your git repo&gt; “, “Starter Pipeline”, and then paste in the following code (You will need to update the ‘azureSubscription’ field with your SPN):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">variables</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">group</span>: <span style="color:#ae81ff">kv-secrets</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pr</span>: <span style="color:#ae81ff">none</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">stages</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">stage</span>: <span style="color:#ae81ff">print_resource_groups</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">jobs</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">job</span>: <span style="color:#ae81ff">print_resource_groups</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">continueOnError</span>: <span style="color:#66d9ef">false</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">task</span>: <span style="color:#ae81ff">AzureCLI@2</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">inputs</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">azureSubscription</span>: <span style="color:#e6db74">&#39;&lt;Your SPN&gt;&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">scriptType</span>: <span style="color:#e6db74">&#39;bash&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">scriptLocation</span>: <span style="color:#e6db74">&#39;inlineScript&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">inlineScript</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az login --service-principal --username $(username) --password $(password) --tenant $(tenantId) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az group list</span> -</span></span></code></pre></div><p>Now click “Save and Run”, and then “Save and Run” again.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-9-1024x596.png"></a></p> -<p>Once the pipeline finishes running, you can see that it was able to read the subscription and create a list of all resource groups found.</p> -<p>This is a simple example of using Key Vault credentials in a pipeline. But you can imagine how useful this could be in more complex scenarios.</p> -<p>That’s all for now. If you have any questions, feel free to reach out!</p> - + http://localhost:1313/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ + This post will cover a secure method for accessing secrets in Azure DevOps pipelines. Why Azure Key Vault? Link to heading Azure Key Vault is an Azure cloud service used to securely store secrets, keys, and certificates. A secret can be any string of characters, such as API keys, passwords, URLs, etc. Azure Key Vault encrypts data at rest and in transit using HTTPS. Depending on the type of Key Vault you are using, data at rest is encrypted using software encryption (AES 256) or HSM-backed keys. - Continuous Deployment Models - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ + http://localhost:1313/posts/2022-01-14-continuous-deployment-models/ Fri, 14 Jan 2022 19:24:01 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ - <p>When deploying new software releases to servers or (insert -as-a-service&gt; here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments.</p> -<h2 id="bluegreen-deployments" >Blue/Green Deployments -<span> - <a href="#bluegreen-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. Instead, it gets deployed to another set of servers (blue) first. Since the blue servers are not currently serving any traffic for users, the deployment has no impact. However, once the deployment has been completed successfully and tested, users will be directed to the new deployment (blue). You can control all user traffic or a subset of user traffic if your load balancer supports it (referred to as ‘Progressive Exposure’).</p> -<p>The next release will then repeat the same process. Blue would be the current production environment, so you would first deploy to the green servers. This model requires two sets of identical hosts and a load balancer or reverse proxy in front of them. If there are any unexpected issues with the new release, it is straightforward to switch back to the previous release. The disadvantage to this type of model is that it requires having redundant environments (and potentially wasted resources). However, this is less of a concern if using container orchestration platforms such as Kubernetes.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/01/2022-01-19_07h57_58-1024x575.png" alt="Blue Green deployment model"></p> -<h2 id="immutable-servers" >Immutable Servers -<span> - <a href="#immutable-servers"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>There is an alternative method of blue/green deployments called “immutable servers”. This method is identical to blue/green deployments as described above. However, after switching user traffic over to the servers with the new release, the old servers are destroyed. They are not used again. This type of model becomes particularly efficient when using a pipeline that is capable of creating servers for you (i.e., Azure DevOps Pipelines)</p> -<h2 id="canary-deployments" >Canary Deployments -<span> - <a href="#canary-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>In a canary deployment, not all users are routed to the new release immediately. Only a limited percentage of users get access to the new release. These users are the canaries. They should be monitored closely, so it is important to be using Not all users are routed to the new release immediately in a canary deployment. Only a limited percentage of users get access to the latest release. These users are the canaries.</p> -<p>Organizations should monitor the canaries closely, so it is essential to be using monitoring software capable of looking at the statistics of a web application from the users’ perspective (for example, Application Insights). The number of canaries can increase until all traffic is directed to the new release over time. The most significant advantage of this method is limited exposure to issues. If a problem appears after the release is deployed, only a small subset of users will experience it. After you fix the issues and redeploy the release, it’s best to select a different group of users to be canaries.</p> -<h2 id="ring-based-deployments" >Ring Based Deployments -<span> - <a href="#ring-based-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>A ring-based deployment has multiple production environments. Each serves a limited number of users, similar to a canary deployment. However, you can have as many production environments as you want with a ring-based deployment. New releases are deployed to the rings one by one over time.</p> -<h2 id="feature-flag-deployments" >Feature Flag Deployments -<span> - <a href="#feature-flag-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Feature flags are used to expose new features to sets of users slowly. Unlike the other deployment models, they are not implemented in the infrastructure. Instead, they are typically implemented and enabled in code or database. An example would be a feature flag in a database that gives users access to a button on your web page. A developer could enable the flag for a set of users. These users would be able to see the button; other users would not. Feature flags can even toggle bug fixes or performance improvements.</p> -<p>I will cover implementing blue/green deployments in Azure using Azure DevOps and App Services in a future article.</p> - + http://localhost:1313/posts/2022-01-14-continuous-deployment-models/ + When deploying new software releases to servers or (insert -as-a-service&gt; here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments. Blue/Green Deployments Link to heading Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. - diff --git a/public/categories/ci/cd/page/1/index.html b/public/categories/ci/cd/page/1/index.html index 09b0ec6e..358050ff 100644 --- a/public/categories/ci/cd/page/1/index.html +++ b/public/categories/ci/cd/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/ci/cd/ - + http://localhost:1313/categories/ci/cd/ + - + diff --git a/public/categories/devops/index.html b/public/categories/devops/index.html index 11e7fd9c..e84b7e86 100644 --- a/public/categories/devops/index.html +++ b/public/categories/devops/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: Devops · GeekyRyan + - - -Devops - GeekyRyan + - + + + - - - + + + - + + + + + + - - - + + + + - - - - - - - - - - - - - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,567 +79,176 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - -
    -
    - -

    Category: Devops

    - - - -
    -
    -
    -

    Using try/catch/finally Blocks in PowerShell

    -
    - -
    - - -
    - Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it’s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we’ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn’t crash when the unexpected occurs. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Golang: When Identical Strings are Not Equal

    -
    - -
    - - -
    - This will be a quick and dirty post, so please forgive any spelling/grammar mistakes. -I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don’t write a ton of code at work (mostly just scripting/pipelines when I do), so I’m constantly working on something like this in my spare time. -
    - - -
    - Read more -
    - - - - - - - -
    - -
    -
    -
    -

    Building a Golang App with Github Actions

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Category: Devops +

    +
    + + + - https://rnemeth90.github.io/posts/2022-12-24-gh-actions-copy/ - Ryan - - -
    - - - - - - -
    -
    - -
    - -
    -
    -
    -

    Chaining YAML Pipelines in Azure Devops

    -
    - -
    - -
    - In this article, we’ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to figure this out. -Our two pipelines will exist in the same repository. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Update Azure Devops SPN Secret

    -
    - -
    - - -
    - If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal. -In this article, I’ll show you two methods for updating a secret for a service principal prior to expiration. -Update the secret via the Azure Devops Portal: Go to “Service Connections” in the Azure Devops portal Find the SPN you want to update, then click “Manage Service Principal” Then on the service principal page, click Certificates & Secrets Create a “New Client Secret”, take note of the value Delete the ‘old’ secret Return to the Service Connection in the Azure Devops portal Click Edit - click the verify button. -
    +
    +
    + © + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - +
    +
    -
    - https://rnemeth90.github.io/posts/2022-09-12-update-azure-devops-spn-secret/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - - + + diff --git a/public/categories/devops/index.xml b/public/categories/devops/index.xml index 143fa4c9..df1c4742 100644 --- a/public/categories/devops/index.xml +++ b/public/categories/devops/index.xml @@ -2,455 +2,46 @@ Devops on GeekyRyan - https://rnemeth90.github.io/categories/devops/ - GeekyRyan (Devops) - Hugo -- gohugo.io - en-us + http://localhost:1313/categories/devops/ + Recent content in Devops on GeekyRyan + Hugo + en Tue, 15 Aug 2023 00:00:00 +0000 - - - - + Using try/catch/finally Blocks in PowerShell - https://rnemeth90.github.io/posts/2023-08-15-powershell-try-catch/ + http://localhost:1313/posts/2023-08-15-powershell-try-catch/ Tue, 15 Aug 2023 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2023-08-15-powershell-try-catch/ - <p>Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it&rsquo;s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we&rsquo;ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn&rsquo;t crash when the unexpected occurs. We&rsquo;ll then cover the differences in terminating and non-terminating errors and why you should take these into consideration when implementing error handling.</p> -<h2 id="the-try-block" >The Try Block -<span> - <a href="#the-try-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The Try block is where you place the code that might generate an error. Think of it as a protective bubble around your potentially troublesome code. If an error occurs within the Try block, PowerShell will immediately jump to the corresponding Catch block.</p> -<p>Here&rsquo;s a simple example:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><h2 id="the-catch-block" >The Catch Block -<span> - <a href="#the-catch-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The Catch block is where you can handle the error. PowerShell provides you with a special variable $_ that contains information about the error. You can use this variable to display error messages or even take corrective actions.</p> -<p>In the example above, we&rsquo;re capturing the error generated by attempting to retrieve a nonexistent file. The $_ variable holds the error message, which we&rsquo;re displaying using Write-Host.</p> -<h2 id="the-finally-block" >The Finally Block -<span> - <a href="#the-finally-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Now, let&rsquo;s talk about the unsung hero – the Finally block. This block is executed regardless of whether an error occurred or not. It&rsquo;s where you can place cleanup code that ensures your script leaves no trace behind, even in the face of adversity. Some tasks that are commonly done in the finally block are closing database connections, removing temp files, etc. The finally block is completely optional.</p> -<pre tabindex="0"><code> -try { - # Code that might generate an error - # ... -} -catch { - # Code to handle the error - # ... -} -finally { - # Cleanup code here - # ... -} -</code></pre><h2 id="terminatingnon-terminating-errors" >Terminating/non-terminating Errors -<span> - <a href="#terminatingnon-terminating-errors"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>non-terminating errors are any error that will not stop the execution of your script. Most cmdlets in PowerShell are non-terminating. They may output an error, but your script will continue to run. These kinds of errors cannot be caught with a catch block by default. The reason for this is the default <code>ErrorAction</code> in your PowerShell profile, which is set to <code>Continue</code>.</p> -<pre tabindex="0"><code># To show your default error action type -$ErrorActionPreference -</code></pre><p>Let&rsquo;s go back and look at our first example:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><p>If you took the time to run this code, you may have noticed that the <code>Write-Host</code> cmdlet in the <code>catch</code> block was never ran. Why did we get a red error message in our PowerShell console, rather than the text <code>An error occurred: ...</code>? The reason is that the non-existing path isn&rsquo;t a terminating error, and the default <code>ErrorAction</code> is <code>Continue</code>. To catch the error, you will need to change the <code>ErrorAction</code> in your PowerShell console to <code>Stop</code>. This can be done in multiple ways. You can add <code>-ErrorAction Stop</code> to the cmdlet, like this:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -ErrorAction Stop -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><p>Or you can change the <code>ErrorActionPreference</code> for the entire script, by adding this to the top of the script:</p> -<pre tabindex="0"><code>$ErrorActionPreference = &#34;Stop&#34; -</code></pre><h2 id="exceptions" >Exceptions -<span> - <a href="#exceptions"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>If you have ever worked with exceptions in C# you can skip this section. In the previous examples, we used simple <code>catch</code> blocks that will catch <em>any</em> error. This is a good start, but we can do better. PowerShell allows you to catch individual exceptions based on the exception type, similar to how C# handles catching exceptions.</p> -<p>Let&rsquo;s look at an example:</p> -<pre tabindex="0"><code>try { - # Attempt to open a non-existent file - $file = Get-Content -Path &#34;NonexistentFile.txt&#34; -} -catch [System.IO.FileNotFoundException] { - Write-Host &#34;Caught a FileNotFoundException: $_&#34; -} -catch { - Write-Host &#34;Caught an exception: $_&#34; -} -</code></pre><p>We now have two <code>catch</code> blocks. If we encounter an exception of type <code>System.IO.FileNotFoundException</code>, the first <code>catch</code> block will catch the exception and handle it accordingly. The second <code>catch</code> block will handle any other generic error.</p> -<h2 id="conclusion" >Conclusion -<span> - <a href="#conclusion"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Error handling might seem daunting at first, but with the power of Try-Catch-Finally blocks at your fingertips, you&rsquo;re well-equipped to handle errors gracefully and ensure the resilience of your PowerShell scripts. Remember, every error is an opportunity to refine your skills and make your scripts more robust.</p> -<p>Thanks for reading!</p> -<p>Official Microsoft Documentation for Try-Catch-Finally in PowerShell: -<a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-7.3">about_try_catch_finally</a></p> - + http://localhost:1313/posts/2023-08-15-powershell-try-catch/ + Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it&rsquo;s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we&rsquo;ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn&rsquo;t crash when the unexpected occurs. - Golang: When Identical Strings are Not Equal - https://rnemeth90.github.io/posts/2023-01-24-golang-strings-not-equal/ + http://localhost:1313/posts/2023-01-24-golang-strings-not-equal/ Tue, 24 Jan 2023 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2023-01-24-golang-strings-not-equal/ - <p><em>This will be a quick and dirty post, so please forgive any spelling/grammar mistakes.</em></p> -<p>I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don&rsquo;t write a ton of code at work (mostly just scripting/pipelines when I do), so I&rsquo;m constantly working on something like this in my spare time. Anyway, I was writing this app, got everything working like I wanted it to. I then wrote some of the tests and was iterating over them. I noticed the <code>ListTasks</code> test was failing:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TestAddTask</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">task</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;test task number 1&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Getwd</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmdPath</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">binaryName</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;AddNewTask&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-add&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">Run</span>(); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// failing test -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;ListTasks&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-list&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">out</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">CombinedOutput</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">expected</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;[ ] 1: %s&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Compare</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#a6e22e">expected</span>) <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;got %v, expected %v\n&#34;</span>, <span style="color:#a6e22e">out</span>, []byte(<span style="color:#a6e22e">expected</span>)) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Seems strange, considering the strings appear to be equivalent in the output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span> main_test.go:82: got <span style="color:#f92672">[</span> <span style="color:#f92672">]</span> 1: test task number <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> , expected <span style="color:#f92672">[</span> <span style="color:#f92672">]</span> 1: test task number <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>--- FAIL: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- FAIL: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>FAIL -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>exit status <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>FAIL github.com/rnemeth90/todo/cmd/todo 0.105s -</span></span></code></pre></div><p>What could be happening? After banging my head on the desk a few times, a revelation came to me&hellip;</p> -<p>In Go, strings are simply slices of bytes. I decided to print out each string as a byte array:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span> main_test.go:80: got <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">10</span> 10<span style="color:#f92672">]</span>, expected <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> 49<span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span>--- FAIL: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- FAIL: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>FAIL -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>exit status <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>FAIL github.com/rnemeth90/todo/cmd/todo 0.144s -</span></span></code></pre></div><p>Let&rsquo;s take a closer look at the byte arrays from the test output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>got <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">10</span> 10<span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span>expected <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> 49<span style="color:#f92672">]</span> -</span></span></code></pre></div><p>We can see the byte array returned from <code>cmd.CombinedOutput()</code> has some additional bytes in it at the end (32,10,10). What exactly are 32, 10, and 10? To figure this out, I went over to the go playground: <a href="https://go.dev/play/">https://go.dev/play/</a>.</p> -<p>Let&rsquo;s see what happens when we create a byte array with a single number and print it out as a string to the console:</p> -<p><a href="https://rnemeth90.github.io/images/golang-strings-not-equal-01.png"><img src="https://rnemeth90.github.io/images/golang-strings-not-equal-01.png" alt=""></a></p> -<p>Interesting, we can see that <code>m</code> was output to the console. So what do our mysterious additional characters in our test result represent? Let&rsquo;s see:</p> -<p><a href="https://rnemeth90.github.io/images/golang-strings-not-equal-02.png"><img src="https://rnemeth90.github.io/images/golang-strings-not-equal-02.png" alt=""></a></p> -<p>It&rsquo;s hard to tell from the output, but if you look in the results pane, you&rsquo;ll see a space and two new lines. So <code>32</code> represents a space, and <code>10</code> represents a new line!</p> -<p>You can play with this code yourself: <a href="https://go.dev/play/p/fGUIxJM6KnV">https://go.dev/play/p/fGUIxJM6KnV</a></p> -<p>Ok, so let&rsquo;s fix our failing test:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TestAddTask</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">task</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;test task number 1&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Getwd</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmdPath</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">binaryName</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;AddNewTask&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-add&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">Run</span>(); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;ListTasks&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-list&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">out</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">CombinedOutput</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// add this line -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">out</span> = []byte(<span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">TrimSuffix</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#e6db74">&#34; \n\n&#34;</span>)) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">expected</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;[ ] 1: %s&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Compare</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#a6e22e">expected</span>) <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;got %v, expected %v\n&#34;</span>, <span style="color:#a6e22e">out</span>, []byte(<span style="color:#a6e22e">expected</span>)) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>The <code>strings</code> package has a <code>TrimSuffix</code> function that is useful for trimming bits off the end of a string. In the code above, you can see that we added <code>out = []byte(strings.TrimSuffix(string(out), &quot; \n\n&quot;))</code>, which will trim off the space (character 32) and the two new lines (character 10). Now when we run our integration test, it passes:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span>--- PASS: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>PASS -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>ok github.com/rnemeth90/todo/cmd/todo 0.106s -</span></span></code></pre></div> + http://localhost:1313/posts/2023-01-24-golang-strings-not-equal/ + This will be a quick and dirty post, so please forgive any spelling/grammar mistakes. I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don&rsquo;t write a ton of code at work (mostly just scripting/pipelines when I do), so I&rsquo;m constantly working on something like this in my spare time. - Building a Golang App with Github Actions - https://rnemeth90.github.io/posts/2022-12-24-gh-actions-copy/ + http://localhost:1313/posts/2022-12-24-gh-actions-copy/ Fri, 23 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-24-gh-actions-copy/ - <p>In this article, we&rsquo;ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app -written in any language though. We&rsquo;ll cover the following:</p> -<ol> -<li>What are github actions?</li> -<li>Setting up the workflow to build, test, and deploy a binary</li> -</ol> -<p>Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. They are powerful and I suggest you read more at the <a href="https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions">Official Docs</a></p> -<p>To get started, we&rsquo;ll need a golang app to build. You can use my example <a href="https://github.com/rnemeth90/golang-github-action-example">here</a> if you do not have your own.</p> -<p>The process is relatively simple. At the root of your repo, create the following directories:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>mkdir -p .github/workflows -</span></span></code></pre></div><p>Then create a yaml file (you can name it anything you want) with the content below:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">name</span>: <span style="color:#ae81ff">build-release-binary</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">run-name</span>: <span style="color:#ae81ff">Create Github Release for GoLang binary</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># anytime we push to our repo with a tag starting with the</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># letter &#39;r&#39;, we run the build</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">on</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">push</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tags</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#e6db74">&#39;r*&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">jobs</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">build</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">runs-on</span>: <span style="color:#ae81ff">ubuntu-22.04</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">permissions</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">contents</span>: <span style="color:#ae81ff">write</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># checkout our github repo to the build agent</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/checkout@v3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">fetch-depth</span>: <span style="color:#ae81ff">0</span> <span style="color:#75715e"># get all tags, needed to get git log</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">ref</span>: <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Setup the Go environment</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">setup Go Lang</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">id</span>: <span style="color:#ae81ff">build</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/setup-go@v3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">go-version</span>: <span style="color:#e6db74">&#39;^1.19.2&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Build our application</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go version -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> cd src -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [ ! -e *.mod ]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go mod init ${GITHUB_REPOSITORY} -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go mod tidy -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go build -ldflags &#34;-X main.Version=${GITHUB_REF_NAME} -X main.BuiltBy=github-actions&#34; main.go -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> execFile=$(find . -type f -executable)</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Output more values for debugging</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git version</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git branch</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git tag</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># tag our release</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">get semantic tag version and release notes from commit messages</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">id</span>: <span style="color:#ae81ff">tag</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">run</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> currentTag=${GITHUB_REF_NAME} -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> major_minor=$(echo &#34;$currentTag&#34; | cut -d&#39;.&#39; -f1-2) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> patch=$(echo &#34;$currentTag&#34; | cut -d&#39;.&#39; -f3) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> # avoid empty patch number -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> [ -n &#34;$patch&#34; ] &amp;&amp; ((patch--)) || patch=&#34;.x&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> previousTag=&#34;${major_minor}.${patch}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;&#34; &gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if git tag | grep $previousTag ; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git log -q ${currentTag}...${previousTag} --pretty=&#34;- %s&#34; -q --no-color &gt;&gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> else -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git log --pretty=&#34;- %s&#34; -q --no-color &gt;&gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> line_count=$(cat body.log | wc -l) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;currentTag=$currentTag&#34; &gt;&gt; $GITHUB_OUTPUT -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;previousTag=$previousTag&#34; &gt;&gt; $GITHUB_OUTPUT -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;line_count=$line_count&#34; &gt;&gt; $GITHUB_OUTPUT</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># create Github release with release note from file and binary asset attached</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">ncipollo/release-action@v1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">${{ env.GITHUB_REF_NAME }}</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tag</span>: <span style="color:#ae81ff">${{ env.GITHUB_REF_NAME }}</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">artifacts</span>: <span style="color:#e6db74">&#34;src/main&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">bodyFile</span>: <span style="color:#e6db74">&#34;body.log&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">token</span>: <span style="color:#ae81ff">${{ secrets.GITHUB_TOKEN }}</span> -</span></span></code></pre></div><p>Each step within this workflow starts with a hyphen. The steps are well-commented, so I will not explain them further. Once you have this file in your repo, push it to github. Then navigate to the Actions tab in your repository and you should see your workflow on the left hand side of the screen.</p> -<p><a href="https://rnemeth90.github.io/images/gh-actions-1.png"><img src="https://rnemeth90.github.io/images/gh-actions-1.png" alt=""></a></p> -<p>Now that we have our workflow setup, to get it run, all you need to do is tag and push your release to github. To do that, you can run the script in my repo <a href="https://github.com/rnemeth90/golang-github-action-example/blob/main/create_new_gh_release.sh">create_new_gh_release.sh</a> or simply run the following commands (be sure to change the tag as needed):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>newtag<span style="color:#f92672">=</span>r1.0.0 -</span></span><span style="display:flex;"><span>git tag $newtag <span style="color:#f92672">&amp;&amp;</span> git push origin $newtag -</span></span></code></pre></div><p>Now, go back to the Actions tab in your repo, and you should see the build running. Once it completes, go back to the Code tab in your github repo and you will see the release on the right hand side of the screen.</p> -<p><a href="https://rnemeth90.github.io/images/gh-actions-2.png"><img src="https://rnemeth90.github.io/images/gh-actions-2.png" alt=""></a></p> - + http://localhost:1313/posts/2022-12-24-gh-actions-copy/ + In this article, we&rsquo;ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app written in any language though. We&rsquo;ll cover the following: What are github actions? Setting up the workflow to build, test, and deploy a binary Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. - Chaining YAML Pipelines in Azure Devops - https://rnemeth90.github.io/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ + http://localhost:1313/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ Thu, 03 Nov 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ - <p>In this article, we&rsquo;ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. -Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to -figure this out.</p> -<p>Our two pipelines will exist in the same repository. We have a dependent-pipeline, that we only want to run once the source-pipeline is finished. This is useful if you have -some infrastructure you want to build, prior to deploying something to that infrastructure.</p> -<p>The process is actually quite simple. First, let&rsquo;s define our source pipeline:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># source-pipeline</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: <span style="color:#ae81ff">echo Hello, world!</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a one-line script&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo Add other tasks to build, test, and deploy your project. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo See https://aka.ms/yaml</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a multi-line script&#39;</span> -</span></span></code></pre></div><p>Nothing fancy here, just the build in template pipeline that Microsoft gives us for free when we create a &ldquo;Starter Pipeline&rdquo;.</p> -<p>Now, let&rsquo;s create another pipeline in the same repo that will be triggered when the pipeline above completes:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># dependent-pipeline</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">none</span> <span style="color:#75715e"># we want this pipeline to be triggered manually, not based on PR, etc.</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">pipelines</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">pipeline</span>: <span style="color:#ae81ff">source-pipeline</span> <span style="color:#75715e">#this can be anything</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">source</span>: <span style="color:#e6db74">&#39;source-pipeline&#39;</span> <span style="color:#75715e">#this needs to be the name of the &#39;source&#39; pipeline</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">trigger</span>: <span style="color:#66d9ef">true</span> <span style="color:#75715e"># Run dependent-pipeline pipeline when any run of security-lib-ci completes</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: <span style="color:#ae81ff">echo Hello, world!</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a one-line script&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo Add other tasks to build, test, and deploy your project. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo See https://aka.ms/yaml</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a multi-line script&#39;</span> -</span></span></code></pre></div><p>The resources block above defines our dependency. You want to be sure to configure the trigger of the dependent pipeline appropriately as well.</p> -<p>There are several options for fine-tuning this process. See the office Microsoft documentation below:</p> -<p><a href="https://learn.microsoft.com/en-us/azure/devops/pipelines/process/pipeline-triggers?view=azure-devops">Link to the Microsoft Docs</a></p> - + http://localhost:1313/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ + In this article, we&rsquo;ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to figure this out. Our two pipelines will exist in the same repository. - Update Azure Devops SPN Secret - https://rnemeth90.github.io/posts/2022-09-12-update-azure-devops-spn-secret/ + http://localhost:1313/posts/2022-09-12-update-azure-devops-spn-secret/ Mon, 12 Sep 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-09-12-update-azure-devops-spn-secret/ - <p>If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal.</p> -<p>In this article, I&rsquo;ll show you two methods for updating a secret for a service principal prior to expiration.</p> -<h1 id="update-the-secret-via-the-azure-devops-portal" >Update the secret via the Azure Devops Portal: -<span> - <a href="#update-the-secret-via-the-azure-devops-portal"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h1><ul> -<li>Go to &ldquo;Service Connections&rdquo; in the Azure Devops portal</li> -<li>Find the SPN you want to update, then click &ldquo;Manage Service Principal&rdquo;</li> -<li>Then on the service principal page, click Certificates &amp; Secrets</li> -<li>Create a &ldquo;New Client Secret&rdquo;, take note of the value</li> -<li>Delete the &lsquo;old&rsquo; secret</li> -<li>Return to the Service Connection in the Azure Devops portal</li> -<li>Click Edit - click the verify button. It should tell you the client certificate has expired</li> -<li>Now you need to make an arbitrary change and save it. I just type a character in the optional description and save.</li> -<li>Now edit again and click verify, it will now pick up the new client secret and all is happy.</li> -<li>You can now remove whatever you added to the description.</li> -</ul> - + http://localhost:1313/posts/2022-09-12-update-azure-devops-spn-secret/ + If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal. In this article, I&rsquo;ll show you two methods for updating a secret for a service principal prior to expiration. Update the secret via the Azure Devops Portal: Link to heading Go to &ldquo;Service Connections&rdquo; in the Azure Devops portal Find the SPN you want to update, then click &ldquo;Manage Service Principal&rdquo; Then on the service principal page, click Certificates &amp; Secrets Create a &ldquo;New Client Secret&rdquo;, take note of the value Delete the &lsquo;old&rsquo; secret Return to the Service Connection in the Azure Devops portal Click Edit - click the verify button. - diff --git a/public/categories/devops/page/1/index.html b/public/categories/devops/page/1/index.html index cc3a20b1..62c81f3b 100644 --- a/public/categories/devops/page/1/index.html +++ b/public/categories/devops/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/devops/ - + http://localhost:1313/categories/devops/ + - + diff --git a/public/categories/docker/index.html b/public/categories/docker/index.html index e5b3ca10..03dfe9f4 100644 --- a/public/categories/docker/index.html +++ b/public/categories/docker/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: Docker · GeekyRyan + - - -Docker - GeekyRyan - - - - - - - - - - + - - + + + - - + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,378 +79,161 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    -
    -
    - -

    Category: Docker

    - + 2022-07-15 + Scheduled Kubernetes Worker Node Maintenance with Kured + +
  • + 2022-06-26 + Running Docker in WSL v1 +
  • -
    -
    -
    -

    Scheduled Kubernetes Worker Node Maintenance with Kured

    -
    - -
    + + - -
    - If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this? -Weaveworks created a great tool for simplifying these steps: Kured (the Kubernetes Reboot Daemon). -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Running Docker in WSL v1

    -
    -
    +
    +
    + © -
    - I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. -Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - +
    +
    -
    - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - - + + diff --git a/public/categories/docker/index.xml b/public/categories/docker/index.xml index 331de15f..f1e2eabe 100644 --- a/public/categories/docker/index.xml +++ b/public/categories/docker/index.xml @@ -2,87 +2,25 @@ Docker on GeekyRyan - https://rnemeth90.github.io/categories/docker/ - GeekyRyan (Docker) - Hugo -- gohugo.io - en-us + http://localhost:1313/categories/docker/ + Recent content in Docker on GeekyRyan + Hugo + en Fri, 15 Jul 2022 18:18:50 +0000 - - - - + Scheduled Kubernetes Worker Node Maintenance with Kured - https://rnemeth90.github.io/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ + http://localhost:1313/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ Fri, 15 Jul 2022 18:18:50 +0000 - - https://rnemeth90.github.io/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ - <p>If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this?</p> -<p>Weaveworks created a great tool for simplifying these steps: Kured (the <em><strong>Ku</strong>bernetes <strong>Re</strong>boot <strong>D</strong>aemon</em>). Let’s start by deploying Kured to our cluster.</p> -<p>Kured can be deployed in one of several ways. In this article, we’ll focus on deploying it via Helm. This is the simplest and quickest way to get it running in our cluster.</p> -<p>Follow these steps to install the Helm chart:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># 1) Add the Kured Helm repository</span> -</span></span><span style="display:flex;"><span>helm repo add kured https://weaveworks.github.io/kured -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 2) Update your local Helm chart repository cache</span> -</span></span><span style="display:flex;"><span>helm repo update -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 3) Create a dedicated namespace where you would like to deploy kured</span> -</span></span><span style="display:flex;"><span>kubectl create namespace kured -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 4) Install kured in that namespace with Helm 3 (only on Linux nodes)</span> -</span></span><span style="display:flex;"><span>helm install kured kured/kured --namespace kured --set nodeSelector.<span style="color:#e6db74">&#34;kubernetes\.io/os&#34;</span><span style="color:#f92672">=</span>linux -</span></span></code></pre></div><p>If all went well with the command above, that’s it, you’re done! Have a nice day! 🙂</p> -<p>If you want to test Kured, login to one of your Linux nodes, and install some patches with your package manager of choice (any patch that requires a reboot, typically patches that modify kernel headers). Then, check for a file named ‘reboot-required’ in /var/run:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>ls -lisa /var/run/reboot-required -</span></span></code></pre></div><p>If you installed patches, and this file does not exist, none of your patches require a reboot. We can still fake the system into thinking a reboot is required by manually creating the ‘reboot-required’ file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo touch /var/run/reboot-required -</span></span></code></pre></div><p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-1.png" alt=""></p> -<p>Then, we’ll use Kubetail to tail the logs of all our Kured pods:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubetail -label kured --namespace kured -</span></span></code></pre></div><p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-1024x749.png" alt=""></p> -<p>By default, Kured checks for the existence of the sentinel file every 60 minutes. However, this behavior can be changed. See the github repo for more info:</p> -<p><img src="https://github.com/weaveworks/kured#reboot-sentinel-file--period" alt="weaveworks/kured: Kubernetes Reboot Daemon"></p> -<p>Scheduling on the node should be disabled if you are within the Kured schedule</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-2.png" alt=""></p> -<p>Now that the node is cordoned off, running pods on the node are drained, and the node is rebooted.</p> -<p>That’s it for this article. Have a great day!</p> - + http://localhost:1313/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ + If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this? Weaveworks created a great tool for simplifying these steps: Kured (the Kubernetes Reboot Daemon). - Running Docker in WSL v1 - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ Sun, 26 Jun 2022 15:00:28 +0000 - - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ - <p>I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate.</p> -<p>Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. I receive this nice message:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ docker -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>The command <span style="color:#e6db74">&#39;docker&#39;</span> could not be found in this WSL <span style="color:#ae81ff">1</span> distro. -</span></span><span style="display:flex;"><span>We recommend to convert this distro to WSL <span style="color:#ae81ff">2</span> and activate -</span></span><span style="display:flex;"><span>the WSL integration in Docker Desktop settings. -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>See https://docs.docker.com/docker-for-windows/wsl/ <span style="color:#66d9ef">for</span> details. -</span></span></code></pre></div><p>So I’m in somewhat of a catch-22 here…</p> -<p>To work around this problem until a proper solution is found, I was able to get Docker working with WSL v1.</p> -<p>If you happen to be having a similar issue (and it seems like quite a few people are, considering the number of Github posts I found), just follow these steps:</p> -<ul> -<li>Expose the Docker daemon in docker desktop settings:</li> -</ul> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/02/image-10-1024x585.png"></a></p> -<p>Install the stand-alone Docker client in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ tar zxvf docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ cd docker -</span></span></code></pre></div><p>Set the default Docker daemon in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>export DOCKER_HOST<span style="color:#f92672">=</span>tcp://localhost:2375 -</span></span></code></pre></div><p>Verify you can connect to Docker running on Windows from within WSL:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>./docker info -</span></span></code></pre></div><p>This is also beneficial in that you only have one Docker host to manage your containers, network, etc., rather than two.</p> - + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ + I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. - diff --git a/public/categories/docker/page/1/index.html b/public/categories/docker/page/1/index.html index 75102da2..f75aadbc 100644 --- a/public/categories/docker/page/1/index.html +++ b/public/categories/docker/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/docker/ - + http://localhost:1313/categories/docker/ + - + diff --git a/public/categories/ef-core/index.html b/public/categories/ef-core/index.html index 5beb593f..e62de06e 100644 --- a/public/categories/ef-core/index.html +++ b/public/categories/ef-core/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: EF Core · GeekyRyan + - - -EF Core - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,306 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Category: EF Core

    - - - -
    -
    -
    -

    EF Core &#8211; Unable to create an object of type DbContext

    -
    -
    +
    +
    + © -
    - This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it! -When running EF Core migrations in a solution, you may come across this error: -There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio. -To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - - + + diff --git a/public/categories/ef-core/index.xml b/public/categories/ef-core/index.xml index d5a5b673..90e02a6b 100644 --- a/public/categories/ef-core/index.xml +++ b/public/categories/ef-core/index.xml @@ -2,31 +2,18 @@ EF Core on GeekyRyan - https://rnemeth90.github.io/categories/ef-core/ - GeekyRyan (EF Core) - Hugo -- gohugo.io - en-us + http://localhost:1313/categories/ef-core/ + Recent content in EF Core on GeekyRyan + Hugo + en Sun, 12 Jun 2022 13:58:52 +0000 - - - - + EF Core &#8211; Unable to create an object of type DbContext - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ Sun, 12 Jun 2022 13:58:52 +0000 - - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ - <p>This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it!</p> -<p>When running EF Core migrations in a solution, you may come across this error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-1-1024x142.png"></a></p> -<p>There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio.</p> -<p>To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-2.png"></a></p> -<p>If you are using clean architecture, or some other architecture that has your startup context and your dbContext in different projects, you will need to set your startup project to your runtime, and the ‘Default Project’ in the package manager console to the project containing your dbContext.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-3-1024x493.png"></a></p> - + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it! When running EF Core migrations in a solution, you may come across this error: There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio. To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’. - diff --git a/public/categories/ef-core/page/1/index.html b/public/categories/ef-core/page/1/index.html index a9ab5829..ddf95cc6 100644 --- a/public/categories/ef-core/page/1/index.html +++ b/public/categories/ef-core/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/ef-core/ - + http://localhost:1313/categories/ef-core/ + - + diff --git a/public/categories/entity-framework-core/index.html b/public/categories/entity-framework-core/index.html index a2026029..9a41e580 100644 --- a/public/categories/entity-framework-core/index.html +++ b/public/categories/entity-framework-core/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: Entity Framework Core · GeekyRyan + - - -Entity Framework Core - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,306 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Category: Entity Framework Core

    - - - -
    -
    -
    -

    EF Core &#8211; Unable to create an object of type DbContext

    -
    -
    +
    +
    + © -
    - This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it! -When running EF Core migrations in a solution, you may come across this error: -There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio. -To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - - + + diff --git a/public/categories/entity-framework-core/index.xml b/public/categories/entity-framework-core/index.xml index 9196d186..c55f57dd 100644 --- a/public/categories/entity-framework-core/index.xml +++ b/public/categories/entity-framework-core/index.xml @@ -2,31 +2,18 @@ Entity Framework Core on GeekyRyan - https://rnemeth90.github.io/categories/entity-framework-core/ - GeekyRyan (Entity Framework Core) - Hugo -- gohugo.io - en-us + http://localhost:1313/categories/entity-framework-core/ + Recent content in Entity Framework Core on GeekyRyan + Hugo + en Sun, 12 Jun 2022 13:58:52 +0000 - - - - + EF Core &#8211; Unable to create an object of type DbContext - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ Sun, 12 Jun 2022 13:58:52 +0000 - - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ - <p>This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it!</p> -<p>When running EF Core migrations in a solution, you may come across this error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-1-1024x142.png"></a></p> -<p>There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio.</p> -<p>To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-2.png"></a></p> -<p>If you are using clean architecture, or some other architecture that has your startup context and your dbContext in different projects, you will need to set your startup project to your runtime, and the ‘Default Project’ in the package manager console to the project containing your dbContext.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-3-1024x493.png"></a></p> - + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it! When running EF Core migrations in a solution, you may come across this error: There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio. To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’. - diff --git a/public/categories/entity-framework-core/page/1/index.html b/public/categories/entity-framework-core/page/1/index.html index 678e3e16..f299dac9 100644 --- a/public/categories/entity-framework-core/page/1/index.html +++ b/public/categories/entity-framework-core/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/entity-framework-core/ - + http://localhost:1313/categories/entity-framework-core/ + - + diff --git a/public/categories/exchange/index.html b/public/categories/exchange/index.html index 267d8390..f3bc70f2 100644 --- a/public/categories/exchange/index.html +++ b/public/categories/exchange/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: Exchange · GeekyRyan + - - -Exchange - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,283 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Category: Exchange

    - - - -
    -
    -
    -

    Exchange 2013: Error 0x80070070 While Adding DAG Member

    -
    -
    +
    +
    + © -
    - Error: A server-side database availability group administrative operation failed. Error Failed to add or remove the Failover-Clustering feature. Error: The request to add or remove features on the specified server failed. A DISM session could not be opened. An error occurred accessing the temporary folder C:WindowsTEMP57ACE2DE-4CD2-4F5F-B7A0-93D867A89A12. Ensure that the path to the temporary folder exists and that you have Read/Write permissions on the folder. Error: 0x80070070 -Solution: I was attempting to remotely add the DAG member from the ECP on my workstation. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2016-10-04-exchange-2013-error-0x80070070-while/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - - + + diff --git a/public/categories/exchange/index.xml b/public/categories/exchange/index.xml index 4dee8131..65f5f9f1 100644 --- a/public/categories/exchange/index.xml +++ b/public/categories/exchange/index.xml @@ -2,25 +2,18 @@ Exchange on GeekyRyan - https://rnemeth90.github.io/categories/exchange/ - GeekyRyan (Exchange) - Hugo -- gohugo.io - en-us + http://localhost:1313/categories/exchange/ + Recent content in Exchange on GeekyRyan + Hugo + en Tue, 04 Oct 2016 00:21:00 +0000 - - - - + Exchange 2013: Error 0x80070070 While Adding DAG Member - https://rnemeth90.github.io/posts/2016-10-04-exchange-2013-error-0x80070070-while/ + http://localhost:1313/posts/2016-10-04-exchange-2013-error-0x80070070-while/ Tue, 04 Oct 2016 00:21:00 +0000 - - https://rnemeth90.github.io/posts/2016-10-04-exchange-2013-error-0x80070070-while/ - <p>Error: A server-side database availability group administrative operation failed. Error Failed to add or remove the Failover-Clustering feature. Error: The request to add or remove features on the specified server failed. A DISM session could not be opened. An error occurred accessing the temporary folder C:WindowsTEMP57ACE2DE-4CD2-4F5F-B7A0-93D867A89A12. Ensure that the path to the temporary folder exists and that you have Read/Write permissions on the folder. Error: 0x80070070</p> -<p>Solution: I was attempting to remotely add the DAG member from the ECP on my workstation. I logged into the server and found that the system drive was nearly full (~100MB free). Luckily this mailbox server was a virtual machine, and I was able to quickly expand the drive using VMM. After doing this I was able to successfully add the mailbox server to the DAG.</p> - + http://localhost:1313/posts/2016-10-04-exchange-2013-error-0x80070070-while/ + Error: A server-side database availability group administrative operation failed. Error Failed to add or remove the Failover-Clustering feature. Error: The request to add or remove features on the specified server failed. A DISM session could not be opened. An error occurred accessing the temporary folder C:WindowsTEMP57ACE2DE-4CD2-4F5F-B7A0-93D867A89A12. Ensure that the path to the temporary folder exists and that you have Read/Write permissions on the folder. Error: 0x80070070 Solution: I was attempting to remotely add the DAG member from the ECP on my workstation. - diff --git a/public/categories/exchange/page/1/index.html b/public/categories/exchange/page/1/index.html index d374182f..492fac30 100644 --- a/public/categories/exchange/page/1/index.html +++ b/public/categories/exchange/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/exchange/ - + http://localhost:1313/categories/exchange/ + - + diff --git a/public/categories/github/index.html b/public/categories/github/index.html index 7e720742..470a1b69 100644 --- a/public/categories/github/index.html +++ b/public/categories/github/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: Github · GeekyRyan + - - -Github - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,295 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Category: Github

    - - - -
    -
    -
    -

    Building a Golang App with Github Actions

    -
    -
    +
    +
    + © -
    - In this article, we’ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app written in any language though. We’ll cover the following: -What are github actions? Setting up the workflow to build, test, and deploy a binary Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-12-24-gh-actions-copy/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - - + + diff --git a/public/categories/github/index.xml b/public/categories/github/index.xml index b11667b3..3720be7b 100644 --- a/public/categories/github/index.xml +++ b/public/categories/github/index.xml @@ -2,118 +2,18 @@ Github on GeekyRyan - https://rnemeth90.github.io/categories/github/ - GeekyRyan (Github) - Hugo -- gohugo.io - en-us + http://localhost:1313/categories/github/ + Recent content in Github on GeekyRyan + Hugo + en Fri, 23 Dec 2022 00:00:00 +0000 - - - - + Building a Golang App with Github Actions - https://rnemeth90.github.io/posts/2022-12-24-gh-actions-copy/ + http://localhost:1313/posts/2022-12-24-gh-actions-copy/ Fri, 23 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-24-gh-actions-copy/ - <p>In this article, we&rsquo;ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app -written in any language though. We&rsquo;ll cover the following:</p> -<ol> -<li>What are github actions?</li> -<li>Setting up the workflow to build, test, and deploy a binary</li> -</ol> -<p>Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. They are powerful and I suggest you read more at the <a href="https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions">Official Docs</a></p> -<p>To get started, we&rsquo;ll need a golang app to build. You can use my example <a href="https://github.com/rnemeth90/golang-github-action-example">here</a> if you do not have your own.</p> -<p>The process is relatively simple. At the root of your repo, create the following directories:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>mkdir -p .github/workflows -</span></span></code></pre></div><p>Then create a yaml file (you can name it anything you want) with the content below:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">name</span>: <span style="color:#ae81ff">build-release-binary</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">run-name</span>: <span style="color:#ae81ff">Create Github Release for GoLang binary</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># anytime we push to our repo with a tag starting with the</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># letter &#39;r&#39;, we run the build</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">on</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">push</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tags</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#e6db74">&#39;r*&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">jobs</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">build</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">runs-on</span>: <span style="color:#ae81ff">ubuntu-22.04</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">permissions</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">contents</span>: <span style="color:#ae81ff">write</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># checkout our github repo to the build agent</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/checkout@v3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">fetch-depth</span>: <span style="color:#ae81ff">0</span> <span style="color:#75715e"># get all tags, needed to get git log</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">ref</span>: <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Setup the Go environment</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">setup Go Lang</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">id</span>: <span style="color:#ae81ff">build</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/setup-go@v3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">go-version</span>: <span style="color:#e6db74">&#39;^1.19.2&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Build our application</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go version -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> cd src -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [ ! -e *.mod ]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go mod init ${GITHUB_REPOSITORY} -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go mod tidy -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go build -ldflags &#34;-X main.Version=${GITHUB_REF_NAME} -X main.BuiltBy=github-actions&#34; main.go -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> execFile=$(find . -type f -executable)</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Output more values for debugging</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git version</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git branch</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git tag</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># tag our release</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">get semantic tag version and release notes from commit messages</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">id</span>: <span style="color:#ae81ff">tag</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">run</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> currentTag=${GITHUB_REF_NAME} -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> major_minor=$(echo &#34;$currentTag&#34; | cut -d&#39;.&#39; -f1-2) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> patch=$(echo &#34;$currentTag&#34; | cut -d&#39;.&#39; -f3) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> # avoid empty patch number -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> [ -n &#34;$patch&#34; ] &amp;&amp; ((patch--)) || patch=&#34;.x&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> previousTag=&#34;${major_minor}.${patch}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;&#34; &gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if git tag | grep $previousTag ; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git log -q ${currentTag}...${previousTag} --pretty=&#34;- %s&#34; -q --no-color &gt;&gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> else -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git log --pretty=&#34;- %s&#34; -q --no-color &gt;&gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> line_count=$(cat body.log | wc -l) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;currentTag=$currentTag&#34; &gt;&gt; $GITHUB_OUTPUT -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;previousTag=$previousTag&#34; &gt;&gt; $GITHUB_OUTPUT -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;line_count=$line_count&#34; &gt;&gt; $GITHUB_OUTPUT</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># create Github release with release note from file and binary asset attached</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">ncipollo/release-action@v1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">${{ env.GITHUB_REF_NAME }}</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tag</span>: <span style="color:#ae81ff">${{ env.GITHUB_REF_NAME }}</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">artifacts</span>: <span style="color:#e6db74">&#34;src/main&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">bodyFile</span>: <span style="color:#e6db74">&#34;body.log&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">token</span>: <span style="color:#ae81ff">${{ secrets.GITHUB_TOKEN }}</span> -</span></span></code></pre></div><p>Each step within this workflow starts with a hyphen. The steps are well-commented, so I will not explain them further. Once you have this file in your repo, push it to github. Then navigate to the Actions tab in your repository and you should see your workflow on the left hand side of the screen.</p> -<p><a href="https://rnemeth90.github.io/images/gh-actions-1.png"><img src="https://rnemeth90.github.io/images/gh-actions-1.png" alt=""></a></p> -<p>Now that we have our workflow setup, to get it run, all you need to do is tag and push your release to github. To do that, you can run the script in my repo <a href="https://github.com/rnemeth90/golang-github-action-example/blob/main/create_new_gh_release.sh">create_new_gh_release.sh</a> or simply run the following commands (be sure to change the tag as needed):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>newtag<span style="color:#f92672">=</span>r1.0.0 -</span></span><span style="display:flex;"><span>git tag $newtag <span style="color:#f92672">&amp;&amp;</span> git push origin $newtag -</span></span></code></pre></div><p>Now, go back to the Actions tab in your repo, and you should see the build running. Once it completes, go back to the Code tab in your github repo and you will see the release on the right hand side of the screen.</p> -<p><a href="https://rnemeth90.github.io/images/gh-actions-2.png"><img src="https://rnemeth90.github.io/images/gh-actions-2.png" alt=""></a></p> - + http://localhost:1313/posts/2022-12-24-gh-actions-copy/ + In this article, we&rsquo;ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app written in any language though. We&rsquo;ll cover the following: What are github actions? Setting up the workflow to build, test, and deploy a binary Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. - diff --git a/public/categories/github/page/1/index.html b/public/categories/github/page/1/index.html index 77b9e910..adbf8320 100644 --- a/public/categories/github/page/1/index.html +++ b/public/categories/github/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/github/ - + http://localhost:1313/categories/github/ + - + diff --git a/public/categories/golang/index.html b/public/categories/golang/index.html index d43a1cc2..b42a16f2 100644 --- a/public/categories/golang/index.html +++ b/public/categories/golang/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: Golang · GeekyRyan + - - -golang - GeekyRyan - - - + - - - + + + - - + + + + + + + + + - + + + + - - - - - - - - - - - - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,436 +79,176 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - + + + - - - - - - - - -
    -
    - -

    Category: golang

    - - - -
    -
    -
    -

    Golang: When Identical Strings are Not Equal

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Category: Golang +

    +
    + +
    +
  • + 2022-07-21 + Reading Json Files with Go +
  • -
    -
    -
    -

    Use “replace” in go.mod to Point to a Local Module

    -
    - -
    + + - -
    - If you want to the local version of a dependency in Go rather than one in a remote repository, use the replace keyword. -The replace line goes above your require statements, like so: -module github.com/rnemeth90/foo replace github.com/rnemeth90/bar => /Users/rnemeth90/Projects/bar require ( github.com/rnemeth90/bar v1.0.0 ) Now when you compile this module go build or go install, it will use your local code rather than the remote dependency. -According to the docs, you do need to make sure that the code you’re pointing to also has a go. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Reading Json Files with Go

    -
    -
    +
    +
    + © -
    - JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting with it, and most public APIs accept JSON in HTTP requests. -In this post, we’ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the JSON data within the file into a memory structure. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - +
    +
    +
    -
    - - - - - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - -
    + + diff --git a/public/categories/golang/index.xml b/public/categories/golang/index.xml index 700dcdf4..3901f624 100644 --- a/public/categories/golang/index.xml +++ b/public/categories/golang/index.xml @@ -1,289 +1,47 @@ - golang on GeekyRyan - https://rnemeth90.github.io/categories/golang/ - GeekyRyan (golang) - Hugo -- gohugo.io - en-us - Tue, 24 Jan 2023 00:00:00 +0000 - - - - + Golang on GeekyRyan + http://localhost:1313/categories/golang/ + Recent content in Golang on GeekyRyan + Hugo + en + Wed, 27 Mar 2024 00:00:00 +0000 + + + Detecting MIME Types in Go + http://localhost:1313/posts/2024-03-27-golang-detect-file-type/ + Wed, 27 Mar 2024 00:00:00 +0000 + http://localhost:1313/posts/2024-03-27-golang-detect-file-type/ + Introduction Link to heading Knowing the type of a file you&rsquo;re working with is not just a matter of curiosity — it&rsquo;s often a necessity. This is especially true when you&rsquo;re deciding whether or not a particular operation can be carried out on that file. Go, with its comprehensive standard library, offers a straightforward approach to identifying a file&rsquo;s MIME type, ensuring that developers have the tools they need to make informed decisions about file manipulation. + + + Validating URLs with Go + http://localhost:1313/posts/2023-12-12-golang-url-validation/ + Tue, 19 Dec 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-12-12-golang-url-validation/ + Introduction Link to heading In this post, we&rsquo;ll take a quick look at URL validation using Golang. It&rsquo;s common to implement URL validation as a task within a HTTP request pipeline, typically as middleware. There are many different definitions of &ldquo;validation&rdquo;. For the purpose of this article, we will simply validate that a URL conforms to a particular text pattern. I often see people (mistakenly) use URL and URI interchangeably. + Golang: When Identical Strings are Not Equal - https://rnemeth90.github.io/posts/2023-01-24-golang-strings-not-equal/ + http://localhost:1313/posts/2023-01-24-golang-strings-not-equal/ Tue, 24 Jan 2023 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2023-01-24-golang-strings-not-equal/ - <p><em>This will be a quick and dirty post, so please forgive any spelling/grammar mistakes.</em></p> -<p>I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don&rsquo;t write a ton of code at work (mostly just scripting/pipelines when I do), so I&rsquo;m constantly working on something like this in my spare time. Anyway, I was writing this app, got everything working like I wanted it to. I then wrote some of the tests and was iterating over them. I noticed the <code>ListTasks</code> test was failing:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TestAddTask</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">task</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;test task number 1&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Getwd</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmdPath</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">binaryName</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;AddNewTask&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-add&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">Run</span>(); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// failing test -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;ListTasks&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-list&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">out</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">CombinedOutput</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">expected</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;[ ] 1: %s&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Compare</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#a6e22e">expected</span>) <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;got %v, expected %v\n&#34;</span>, <span style="color:#a6e22e">out</span>, []byte(<span style="color:#a6e22e">expected</span>)) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Seems strange, considering the strings appear to be equivalent in the output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span> main_test.go:82: got <span style="color:#f92672">[</span> <span style="color:#f92672">]</span> 1: test task number <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> , expected <span style="color:#f92672">[</span> <span style="color:#f92672">]</span> 1: test task number <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>--- FAIL: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- FAIL: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>FAIL -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>exit status <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>FAIL github.com/rnemeth90/todo/cmd/todo 0.105s -</span></span></code></pre></div><p>What could be happening? After banging my head on the desk a few times, a revelation came to me&hellip;</p> -<p>In Go, strings are simply slices of bytes. I decided to print out each string as a byte array:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span> main_test.go:80: got <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">10</span> 10<span style="color:#f92672">]</span>, expected <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> 49<span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span>--- FAIL: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- FAIL: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>FAIL -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>exit status <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>FAIL github.com/rnemeth90/todo/cmd/todo 0.144s -</span></span></code></pre></div><p>Let&rsquo;s take a closer look at the byte arrays from the test output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>got <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">10</span> 10<span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span>expected <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> 49<span style="color:#f92672">]</span> -</span></span></code></pre></div><p>We can see the byte array returned from <code>cmd.CombinedOutput()</code> has some additional bytes in it at the end (32,10,10). What exactly are 32, 10, and 10? To figure this out, I went over to the go playground: <a href="https://go.dev/play/">https://go.dev/play/</a>.</p> -<p>Let&rsquo;s see what happens when we create a byte array with a single number and print it out as a string to the console:</p> -<p><a href="https://rnemeth90.github.io/images/golang-strings-not-equal-01.png"><img src="https://rnemeth90.github.io/images/golang-strings-not-equal-01.png" alt=""></a></p> -<p>Interesting, we can see that <code>m</code> was output to the console. So what do our mysterious additional characters in our test result represent? Let&rsquo;s see:</p> -<p><a href="https://rnemeth90.github.io/images/golang-strings-not-equal-02.png"><img src="https://rnemeth90.github.io/images/golang-strings-not-equal-02.png" alt=""></a></p> -<p>It&rsquo;s hard to tell from the output, but if you look in the results pane, you&rsquo;ll see a space and two new lines. So <code>32</code> represents a space, and <code>10</code> represents a new line!</p> -<p>You can play with this code yourself: <a href="https://go.dev/play/p/fGUIxJM6KnV">https://go.dev/play/p/fGUIxJM6KnV</a></p> -<p>Ok, so let&rsquo;s fix our failing test:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TestAddTask</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">task</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;test task number 1&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Getwd</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmdPath</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">binaryName</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;AddNewTask&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-add&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">Run</span>(); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;ListTasks&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-list&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">out</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">CombinedOutput</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// add this line -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">out</span> = []byte(<span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">TrimSuffix</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#e6db74">&#34; \n\n&#34;</span>)) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">expected</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;[ ] 1: %s&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Compare</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#a6e22e">expected</span>) <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;got %v, expected %v\n&#34;</span>, <span style="color:#a6e22e">out</span>, []byte(<span style="color:#a6e22e">expected</span>)) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>The <code>strings</code> package has a <code>TrimSuffix</code> function that is useful for trimming bits off the end of a string. In the code above, you can see that we added <code>out = []byte(strings.TrimSuffix(string(out), &quot; \n\n&quot;))</code>, which will trim off the space (character 32) and the two new lines (character 10). Now when we run our integration test, it passes:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span>--- PASS: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>PASS -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>ok github.com/rnemeth90/todo/cmd/todo 0.106s -</span></span></code></pre></div> + http://localhost:1313/posts/2023-01-24-golang-strings-not-equal/ + This will be a quick and dirty post, so please forgive any spelling/grammar mistakes. I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don&rsquo;t write a ton of code at work (mostly just scripting/pipelines when I do), so I&rsquo;m constantly working on something like this in my spare time. - Use “replace” in go.mod to Point to a Local Module - https://rnemeth90.github.io/posts/2022-09-06-go-mod-replace-copy/ + http://localhost:1313/posts/2022-09-06-go-mod-replace-copy/ Tue, 06 Sep 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-09-06-go-mod-replace-copy/ - <p>If you want to the local version of a dependency in Go rather than one in a remote repository, use the <em>replace</em> keyword.</p> -<p>The replace line goes above your require statements, like so:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> module github.com/rnemeth90/foo -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> replace github.com/rnemeth90/bar <span style="color:#f92672">=</span>&gt; /Users/rnemeth90/Projects/bar -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> require <span style="color:#f92672">(</span> -</span></span><span style="display:flex;"><span> github.com/rnemeth90/bar v1.0.0 -</span></span><span style="display:flex;"><span> <span style="color:#f92672">)</span> -</span></span></code></pre></div><p>Now when you compile this module <em>go build</em> or <em>go install</em>, it will use your local code rather than the remote dependency.</p> -<p>According to the docs, you do need to make sure that the code you’re pointing to also has a <strong>go.mod</strong> file:</p> -<blockquote> -<p><strong>Note</strong>: if the right-hand side of a <code>replace</code> directive is a filesystem path, then the target must have a <code>go.mod</code> file at that location. If the <code>go.mod</code> file is not present, you can create one with <code>go mod init</code>.</p> -<p><a href="https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive">https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive</a></p> -</blockquote> -<p>You can also create this line from the command line using the <strong>go mod edit</strong> command.</p> -<pre><code>$ go mod edit -replace github.com/rnemeth90/bar=/Users/rnemeth90/Projects/bar -</code></pre> -<p>Following the <strong>-replace</strong> is first what you want to replace, then an equals sign, then what you’re replacing it with.</p> -<p>Hopefully this helps someone who was stuck with this like me 🙂</p> - + http://localhost:1313/posts/2022-09-06-go-mod-replace-copy/ + If you want to the local version of a dependency in Go rather than one in a remote repository, use the replace keyword. The replace line goes above your require statements, like so: module github.com/rnemeth90/foo replace github.com/rnemeth90/bar =&gt; /Users/rnemeth90/Projects/bar require ( github.com/rnemeth90/bar v1.0.0 ) Now when you compile this module go build or go install, it will use your local code rather than the remote dependency. According to the docs, you do need to make sure that the code you’re pointing to also has a go. - Reading Json Files with Go - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ + http://localhost:1313/posts/2022-07-21-reading-json-files-with-go/ Thu, 21 Jul 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ - <p>JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting -with it, and most public APIs accept JSON in HTTP requests.</p> -<p>In this post, we&rsquo;ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the -JSON data within the file into a memory structure.</p> -<p>Let&rsquo;s assume we have the following JSON data representing an employee:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">1</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Steve&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Rogers&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Captain America&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Department&#34;</span>: <span style="color:#e6db74">&#34;Avengers&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>We need a way of representing this data in memory when decoding it from JSON. For this, we will need to create a struct:</p> -<p>We will build up our go module as we progress through the article</p> -<p>Let&rsquo;s start:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#75715e">// main.go -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> ( -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;encoding/json&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;fmt&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;io/ioutil&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;log&#34;</span> -</span></span><span style="display:flex;"><span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">// Hero represents an hero -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// ALL fields must be exportable! Otherwise the JSON parsing will fail. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Hero</span> <span style="color:#66d9ef">struct</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Id</span> <span style="color:#66d9ef">int</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">FirstName</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">LastName</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Alias</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Group</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() { -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Here we set the log prefix. When reading stack traces, this makes it easier to know -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// where a failure occurred. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">SetPrefix</span>(<span style="color:#e6db74">&#34;main(): &#34;</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// We first need to load the JSON file into memory -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">content</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">ioutil</span>.<span style="color:#a6e22e">ReadFile</span>(<span style="color:#e6db74">&#34;./heros.json&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#e6db74">&#34;Error opening the file: &#34;</span>, <span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Now we parse the JSON data into a memory structure. We know our JSON file will have more than one hero object, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// so we&#39;ll use make() to create a []Hero slice. Since go is a pass-by-value language, we will then use the address-of -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// operator (&amp;) to unmarshal our json data into the heros slice -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">heros</span> <span style="color:#f92672">:=</span> make([]<span style="color:#a6e22e">Hero</span>, <span style="color:#ae81ff">5</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">json</span>.<span style="color:#a6e22e">Unmarshal</span>(<span style="color:#a6e22e">content</span>, <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">heros</span>) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#e6db74">&#34;Error occurred during unmarshal: &#34;</span>, <span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// now we can read/interact with the data. We&#39;ll loop over the array -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// and print the values in memory -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; len(<span style="color:#a6e22e">heros</span>); <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">Id</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">FirstName</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">LastName</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">Group</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Create a file named employees.json with similar data:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>[ -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">1</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Steve&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Rogers&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Captain America&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;group&#34;</span>: <span style="color:#e6db74">&#34;Avengers&#34;</span> -</span></span><span style="display:flex;"><span> }, -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">2</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Clark&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Kent&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Superman&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;group&#34;</span>: <span style="color:#e6db74">&#34;Justice League&#34;</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>] -</span></span></code></pre></div><p>Now, we can run our main.go file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>11:40:47 ryan@xerxes json → go run main.go -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>Steve -</span></span><span style="display:flex;"><span>Rogers -</span></span><span style="display:flex;"><span>Avengers -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span>Clark -</span></span><span style="display:flex;"><span>Kent -</span></span><span style="display:flex;"><span>Justice League -</span></span><span style="display:flex;"><span>11:40:49 ryan@xerxes json -</span></span></code></pre></div><p>Pretty simple! That&rsquo;s why I love go. We accomplished all of this with ~50 lines of code. -Doing something similar in asp.net project would easily double that count and involve creating -multiple files! (nothing against asp.net or c#, I think c# is a great language and use it daily)</p> -<p>Now, &lsquo;go&rsquo; try this!</p> - + http://localhost:1313/posts/2022-07-21-reading-json-files-with-go/ + JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting with it, and most public APIs accept JSON in HTTP requests. In this post, we&rsquo;ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the JSON data within the file into a memory structure. - diff --git a/public/categories/golang/page/1/index.html b/public/categories/golang/page/1/index.html index bdc3d33f..7457e68b 100644 --- a/public/categories/golang/page/1/index.html +++ b/public/categories/golang/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/golang/ - + http://localhost:1313/categories/golang/ + - + diff --git a/public/categories/index.html b/public/categories/index.html index 24d5754e..c453ff8f 100644 --- a/public/categories/index.html +++ b/public/categories/index.html @@ -1,525 +1,520 @@ + - - - - - - - + + Categories · GeekyRyan + - + -Categories - GeekyRyan - + + + - - - + + + + + + + + + - - + - + + + + + + - - - - - - - - - - + - + + + - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - + + + +
    + + + +
    +
    + + + +
    + +
    +
    +

    + Categories +

    +
    + +
    - -
    - + + +
    + + + + + + - - -
    - -
    - -
    + -

    Categories

    - + + -
    - - + - - + + diff --git a/public/categories/index.xml b/public/categories/index.xml index 1865a368..dd4e011e 100644 --- a/public/categories/index.xml +++ b/public/categories/index.xml @@ -2,14 +2,200 @@ Categories on GeekyRyan - https://rnemeth90.github.io/categories/ - GeekyRyan (Categories) - Hugo -- gohugo.io - en-us - Tue, 15 Aug 2023 00:00:00 +0000 - - - - + http://localhost:1313/categories/ + Recent content in Categories on GeekyRyan + Hugo + en + Sat, 29 Jun 2024 00:00:00 +0000 + + + Kubernetes + http://localhost:1313/categories/kubernetes/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/kubernetes/ + + + + Golang + http://localhost:1313/categories/golang/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/golang/ + + + + Software Development + http://localhost:1313/categories/software-development/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/software-development/ + + + + Web Development + http://localhost:1313/categories/web-development/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/web-development/ + + + + Nginx + http://localhost:1313/categories/nginx/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/nginx/ + + + + Linux + http://localhost:1313/categories/linux/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/linux/ + + + + Netcat + http://localhost:1313/categories/netcat/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/netcat/ + + + + Networking + http://localhost:1313/categories/networking/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/networking/ + + + + Devops + http://localhost:1313/categories/devops/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/devops/ + + + + PowerShell + http://localhost:1313/categories/powershell/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/powershell/ + + + + SRE + http://localhost:1313/categories/sre/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/sre/ + + + + Azure + http://localhost:1313/categories/azure/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/azure/ + + + + Synology + http://localhost:1313/categories/synology/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/synology/ + + + + Github + http://localhost:1313/categories/github/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/github/ + + + + Azure Devops + http://localhost:1313/categories/azure-devops/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/azure-devops/ + + + + Azure Kubernetes Service + http://localhost:1313/categories/azure-kubernetes-service/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/azure-kubernetes-service/ + + + + Docker + http://localhost:1313/categories/docker/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/docker/ + + + + Software Deployment + http://localhost:1313/categories/software-deployment/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/software-deployment/ + + + + .NET + http://localhost:1313/categories/.net/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/.net/ + + + + .NET Core + http://localhost:1313/categories/.net-core/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/.net-core/ + + + + C# + http://localhost:1313/categories/c%23/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/c%23/ + + + + EF Core + http://localhost:1313/categories/ef-core/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/ef-core/ + + + + Entity Framework Core + http://localhost:1313/categories/entity-framework-core/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/entity-framework-core/ + + + + Uncategorized + http://localhost:1313/categories/uncategorized/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/uncategorized/ + + + + CI/CD + http://localhost:1313/categories/ci/cd/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/ci/cd/ + + + + SFTP + http://localhost:1313/categories/sftp/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/sftp/ + + + + Exchange + http://localhost:1313/categories/exchange/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/categories/exchange/ + + diff --git a/public/categories/kubernetes/index.html b/public/categories/kubernetes/index.html index 1bed11c2..50d55c8c 100644 --- a/public/categories/kubernetes/index.html +++ b/public/categories/kubernetes/index.html @@ -1,852 +1,269 @@ + - - - - - - - + + Category: Kubernetes · GeekyRyan + - + -kubernetes - GeekyRyan - + + + - - - + + + + + + + + + - - - - + + + + + + + - - - - - - - - - + - + + + - - - - - - - - - - + + + + + + + - - - - + - - - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - -
    -
    - -

    Category: kubernetes

    - - - -
    -
    -
    -

    Handling Graceful Shutdown in a .NET App Hosted in Kubernetes

    -
    - -
    - - -
    - I was recently involved with troubleshooting some API’s hosted in Kubernetes throwing http/502’s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    AKS Scale Down Mode

    -
    - -
    - - -
    - By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete or deallocate nodes. -Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Scheduled Kubernetes Worker Node Maintenance with Kured

    -
    - -
    - - -
    - If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this? -Weaveworks created a great tool for simplifying these steps: Kured (the Kubernetes Reboot Daemon). -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Running Docker in WSL v1

    -
    - -
    - - -
    - I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. -Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. -
    - - -
    - Read more -
    - - - - - - - -
    - -
    -
    -
    -

    Remove Kubernetes Namespace Stuck in the Terminating State

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Category: Kubernetes +

    +
    + +
    +
  • + 2022-02-05 + Kubernetes Pod Eviction +
  • -
    -
    -
    -

    Kubernetes Storage Simplified

    -
    - -
    + + - -
    - In this blog post, we will attempt to explain the current storage options that exist in Kubernetes. If you are new to Kubernetes, learning about its capabilities of managing the application state can be a daunting task. -Container images are built-in layers, with the runtime layer being writable. However, any files on this writable layer are only available for the container’s lifetime. We can mount a volume to a directory inside the container to have persistent data. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Kubernetes Pod Eviction

    -
    -
    +
    +
    + © -
    - In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation. -What is Pod Eviction? Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - - + + diff --git a/public/categories/kubernetes/index.xml b/public/categories/kubernetes/index.xml index 9f41fd45..3f33fcec 100644 --- a/public/categories/kubernetes/index.xml +++ b/public/categories/kubernetes/index.xml @@ -1,583 +1,68 @@ - kubernetes on GeekyRyan - https://rnemeth90.github.io/categories/kubernetes/ - GeekyRyan (kubernetes) - Hugo -- gohugo.io - en-us - Wed, 28 Dec 2022 00:00:00 +0000 - - - - + Kubernetes on GeekyRyan + http://localhost:1313/categories/kubernetes/ + Recent content in Kubernetes on GeekyRyan + Hugo + en + Sat, 29 Jun 2024 00:00:00 +0000 + + + Mounting Multiple Kubernetes Secrets into One Directory + http://localhost:1313/posts/2024-06-29-mount-multiple-kubernetes-secrets-into-one-directory/ + Sat, 29 Jun 2024 00:00:00 +0000 + http://localhost:1313/posts/2024-06-29-mount-multiple-kubernetes-secrets-into-one-directory/ + Introduction Link to heading Combining multiple Kubernetes secrets into a single directory can streamline secret management in your applications. This guide walks you through the process of achieving this in Kubernetes, ensuring efficient and organized secret management. Creating Secrets Link to heading First, create your secrets using the kubectl create secret command: kubectl create secret generic secret-one --from-literal=key1=value1 kubectl create secret generic secret-two --from-literal=key2=value2 Each secret can contain multiple key-value pairs, and you can add more secrets as needed. + Handling Graceful Shutdown in a .NET App Hosted in Kubernetes - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ Wed, 28 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ - <p>I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. It was actually a combination of these blogs (and the resolutions posted) that ended up resolving our issue.</p> -<h3 id="so-what-was-actually-causing-the-502s" >So what was actually causing the 502&rsquo;s? -<span> - <a href="#so-what-was-actually-causing-the-502s"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h3><p>As stated, these APIs are hosted in Kubernetes. They are written primarily in c# (.NET Framework) and hosted in Windows Server Core containers. The pods are load balanced using a service, and we have an Nginx ingress on top of the service. Nothing fancy, just a typical setup that you may have seen or even built yourself. We implement automatic scaling for our replica sets using a standard Kubernetes-native HPA or Keda, depending on the app. We have autoscale rules defined for the pods. Our clusters are hosted in Azure Kubernetes Service, and we autoscale our node pools. So, there are several layers of scaling happening in our clusters at any given time. Occasionally, when a pod was handling a client request, Kubelet or a controller would come along and scale the pod in. We were initially under the belief that the <code>terminationGracePeriodSeconds</code> value within our deployment would allow the pod to continue running for the defined number of seconds. However, we were mistaken. This value tells Kubernetes to allow the application running within the pod some time to clean up. It does <em>not</em> tell the app to continue running for the defined number of seconds after it receives a sigterm signal. This logic actually needs to be implemented within the application itself, or with a prestop hook. The prestop method is <a href="https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/">well documented</a>, so I will not cover it here.</p> -<p>To implement this in a .NET Framework app running in Windows, you need to add this registry key to your container.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">RUN</span> reg add hklm<span style="color:#ae81ff">\s</span>ystem<span style="color:#ae81ff">\c</span>urrentcontrolset<span style="color:#ae81ff">\c</span>ontrol /v WaitToKillServiceTimeout /t REG_SZ /d <span style="color:#ae81ff">60000</span> /f<span style="color:#960050;background-color:#1e0010"> -</span></span></span></code></pre></div><p>This value tells Windows to wait a number of milliseconds before shutting down Normally, Windows only waits for 5 seconds (default) before shutting down any &lsquo;background&rsquo; processes. Windows forcibly shuts down processes after this period of time.</p> -<p>Next, in the startup class, we&rsquo;ll add the following code. I have added inline comments to explain.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c#" data-lang="c#"><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">namespace</span> MyApp.APIConsoleHost -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Program</span> -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Register the SetConsoleCtrlHandler function in kernel32.dll in the -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> application to capture CTRL_SHUTDOWN_EVENT events for resource reclamation -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e"> [DllImport(&#34;Kernel32&#34;)]</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">extern</span> <span style="color:#66d9ef">bool</span> SetConsoleCtrlHandler(HandlerRoutine handler, <span style="color:#66d9ef">bool</span> <span style="color:#66d9ef">add</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Define a delegate for our handler routine</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">delegate</span> <span style="color:#66d9ef">bool</span> HandlerRoutine(CtrlTypes ctrlType); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">volatile</span> ManualResetEvent _exitEvent = <span style="color:#66d9ef">new</span> ManualResetEvent(<span style="color:#66d9ef">false</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> HandlerRoutine _handler; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Define the event types that we want to handle when the application receives a SIGTERM -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_C_EVENT = 0, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_BREAK_EVENT = 1, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_CLOSE_EVENT = 2, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_LOGOFF_EVENT = 5, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_SHUTDOWN_EVENT = 6 -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">enum</span> CtrlTypes -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> CTRL_SHUTDOWN_EVENT = <span style="color:#ae81ff">6</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Here we are defining how we want to handle the shutdown -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We get a timeout value from an env variable named APP_SHUTDOWN_TIMEOUT -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> If that env variable is not found, we default to 60 seconds. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We then switch on our CtrlTypes enum and handle each value accordingly, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then return true. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">bool</span> ConsoleCtrlCheck(CtrlTypes ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> timeout = ConfigurationManager.AppSettings[<span style="color:#e6db74">&#34;APP_SHUTDOWN_TIMEOUT&#34;</span>]; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> (<span style="color:#66d9ef">string</span>.IsNullOrEmpty(timeout)) { timeout = <span style="color:#e6db74">&#34;60&#34;</span>; } -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">int</span> counter = <span style="color:#66d9ef">int</span>.Parse(timeout); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">switch</span> (ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> CtrlTypes.CTRL_SHUTDOWN_EVENT: -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] CTRL_SHUTDOWN received&#34;</span>); -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] Web Server is stopping in {counter} seconds&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">while</span> (counter &gt; <span style="color:#ae81ff">0</span>) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> Thread.Sleep(TimeSpan.FromSeconds(<span style="color:#ae81ff">1</span>)); -</span></span><span style="display:flex;"><span> counter--; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.Set(); -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span>; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span>: -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">false</span>; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Our main method is pretty standard. However, we first register a new handler (_handler), -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then pass it to to the SetConsoleCtrlHandler() method we imported from Kernel32.dll. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> The only other &#39;unique&#39; thing is the _exitEvent.WaitOne(); call defined at the bottom of main(). -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> This is necessary so that main does not immediately exit, and wait&#39;s for a signal. We defined a -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> property for this _exitEvent of type ManualResetEvent at the top of this class file. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> Main(<span style="color:#66d9ef">string</span>[] args) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> _handler += <span style="color:#66d9ef">new</span> HandlerRoutine(ConsoleCtrlCheck); -</span></span><span style="display:flex;"><span> SetConsoleCtrlHandler(_handler, <span style="color:#66d9ef">true</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = BuildStartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> WebApp.Start&lt;SelfHostStartup&gt;(startOptions); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">&#34;Press CTRL+C to stop it&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.WaitOne(); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> StartOptions BuildStartOptions() -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = <span style="color:#66d9ef">new</span> StartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted start options</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> startOptions; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>To prevent the HandlerRoutine instance from being recycled by the GC before the program exits, the HandlerRoutine must be static (as seen in the above example). This is important because if the handlerroutine is recycled before the application is finished, it will throw an error, as shown here:</p> -<pre tabindex="0"><code>A callback was made on a garbage collected delegate of type &#39;Program+HandlerRoutine::Invoke&#39;. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called. -</code></pre> + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. - AKS Scale Down Mode - https://rnemeth90.github.io/posts/2022-07-19-aks-scale-down-mode/ + http://localhost:1313/posts/2022-07-19-aks-scale-down-mode/ Tue, 19 Jul 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-07-19-aks-scale-down-mode/ - <p>By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete <em>or</em> deallocate nodes.</p> -<p>Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. However, you will still need to pay for any storage that the node is using. Having persistent storage also means that any container images that were cached on the node will still be there when the node starts back up. This can be a major performance benefit if you are using Windows containers because the images for these containers are typically very large.</p> -<p>Scale down mode can be configured in several ways. Here, we will look at configuring it via the Azure CLI and Terraform.</p> -<p>Azure CLI:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>az aks nodepool update --scale-down-mode Deallocate --name nplinux01 --cluster-name myAKSCluster --resource-group myResourceGroup -</span></span></code></pre></div><p>Terraform:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-hcl" data-lang="hcl"><span style="display:flex;"><span><span style="color:#66d9ef">resource</span> <span style="color:#e6db74">&#34;azurerm_kubernetes_cluster_node_pool&#34; &#34;nodepool&#34;</span> { -</span></span><span style="display:flex;"><span> name <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;nplinux01&#34;</span> -</span></span><span style="display:flex;"><span> kubernetes_cluster_id <span style="color:#f92672">=</span> <span style="color:#66d9ef">azurerm_kubernetes_cluster</span>.<span style="color:#66d9ef">example</span>.<span style="color:#66d9ef">id</span> -</span></span><span style="display:flex;"><span> vm_size <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Standard_DS2_v2&#34;</span> -</span></span><span style="display:flex;"><span> node_count <span style="color:#f92672">=</span> <span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span> scale_down_mode <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Deallocate&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> tags <span style="color:#f92672">=</span> { -</span></span><span style="display:flex;"><span> Environment <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;lab&#34;</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><em>At the time of this writing, Terraform does not support configuring scale-down mode for the default AKS node pool.</em> -<em>Node pools using ephemeral disks do not support &lsquo;deallocate&rsquo; mode</em></p> - + http://localhost:1313/posts/2022-07-19-aks-scale-down-mode/ + By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete or deallocate nodes. Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. - Scheduled Kubernetes Worker Node Maintenance with Kured - https://rnemeth90.github.io/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ + http://localhost:1313/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ Fri, 15 Jul 2022 18:18:50 +0000 - - https://rnemeth90.github.io/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ - <p>If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this?</p> -<p>Weaveworks created a great tool for simplifying these steps: Kured (the <em><strong>Ku</strong>bernetes <strong>Re</strong>boot <strong>D</strong>aemon</em>). Let’s start by deploying Kured to our cluster.</p> -<p>Kured can be deployed in one of several ways. In this article, we’ll focus on deploying it via Helm. This is the simplest and quickest way to get it running in our cluster.</p> -<p>Follow these steps to install the Helm chart:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># 1) Add the Kured Helm repository</span> -</span></span><span style="display:flex;"><span>helm repo add kured https://weaveworks.github.io/kured -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 2) Update your local Helm chart repository cache</span> -</span></span><span style="display:flex;"><span>helm repo update -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 3) Create a dedicated namespace where you would like to deploy kured</span> -</span></span><span style="display:flex;"><span>kubectl create namespace kured -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 4) Install kured in that namespace with Helm 3 (only on Linux nodes)</span> -</span></span><span style="display:flex;"><span>helm install kured kured/kured --namespace kured --set nodeSelector.<span style="color:#e6db74">&#34;kubernetes\.io/os&#34;</span><span style="color:#f92672">=</span>linux -</span></span></code></pre></div><p>If all went well with the command above, that’s it, you’re done! Have a nice day! 🙂</p> -<p>If you want to test Kured, login to one of your Linux nodes, and install some patches with your package manager of choice (any patch that requires a reboot, typically patches that modify kernel headers). Then, check for a file named ‘reboot-required’ in /var/run:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>ls -lisa /var/run/reboot-required -</span></span></code></pre></div><p>If you installed patches, and this file does not exist, none of your patches require a reboot. We can still fake the system into thinking a reboot is required by manually creating the ‘reboot-required’ file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo touch /var/run/reboot-required -</span></span></code></pre></div><p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-1.png" alt=""></p> -<p>Then, we’ll use Kubetail to tail the logs of all our Kured pods:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubetail -label kured --namespace kured -</span></span></code></pre></div><p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-1024x749.png" alt=""></p> -<p>By default, Kured checks for the existence of the sentinel file every 60 minutes. However, this behavior can be changed. See the github repo for more info:</p> -<p><img src="https://github.com/weaveworks/kured#reboot-sentinel-file--period" alt="weaveworks/kured: Kubernetes Reboot Daemon"></p> -<p>Scheduling on the node should be disabled if you are within the Kured schedule</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-2.png" alt=""></p> -<p>Now that the node is cordoned off, running pods on the node are drained, and the node is rebooted.</p> -<p>That’s it for this article. Have a great day!</p> - + http://localhost:1313/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ + If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this? Weaveworks created a great tool for simplifying these steps: Kured (the Kubernetes Reboot Daemon). - Running Docker in WSL v1 - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ Sun, 26 Jun 2022 15:00:28 +0000 - - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ - <p>I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate.</p> -<p>Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. I receive this nice message:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ docker -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>The command <span style="color:#e6db74">&#39;docker&#39;</span> could not be found in this WSL <span style="color:#ae81ff">1</span> distro. -</span></span><span style="display:flex;"><span>We recommend to convert this distro to WSL <span style="color:#ae81ff">2</span> and activate -</span></span><span style="display:flex;"><span>the WSL integration in Docker Desktop settings. -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>See https://docs.docker.com/docker-for-windows/wsl/ <span style="color:#66d9ef">for</span> details. -</span></span></code></pre></div><p>So I’m in somewhat of a catch-22 here…</p> -<p>To work around this problem until a proper solution is found, I was able to get Docker working with WSL v1.</p> -<p>If you happen to be having a similar issue (and it seems like quite a few people are, considering the number of Github posts I found), just follow these steps:</p> -<ul> -<li>Expose the Docker daemon in docker desktop settings:</li> -</ul> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/02/image-10-1024x585.png"></a></p> -<p>Install the stand-alone Docker client in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ tar zxvf docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ cd docker -</span></span></code></pre></div><p>Set the default Docker daemon in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>export DOCKER_HOST<span style="color:#f92672">=</span>tcp://localhost:2375 -</span></span></code></pre></div><p>Verify you can connect to Docker running on Windows from within WSL:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>./docker info -</span></span></code></pre></div><p>This is also beneficial in that you only have one Docker host to manage your containers, network, etc., rather than two.</p> - + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ + I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. - Remove Kubernetes Namespace Stuck in the Terminating State - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ Sat, 04 Jun 2022 18:29:41 +0000 - - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ - <p>In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state.</p> -<p>A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. One day, you decide you no longer want this blog, so you plan to delete it. Rather than tediously deleting all of the various entities associated with this blog, you can delete the namespace that contains these entities. This will essentially ‘cascade delete’ the resources within the namespace as well.</p> -<p>After deleting the namespace for your blog, you notice that it still exists, but the state of it is ‘Terminating’, and it has been like this for a long time (hours or maybe even days).</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/06/image.png"></a></p> -<p>Kubernetes will occassionally fail to delete third-party resources when deleting a namespace, causing the namespace to linger. This can happen if the third-party API managing the resource is not responding to requests. To verify if any of these resources still exist, use this command:</p> -<pre tabindex="0"><code>kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get --show-kind --show-all --ignore-not-found -n &lt;terminating-namespace&gt; -</code></pre><p>If you happen to see any resources in the output, you can try force deleting them and then try to delete the namespace again.</p> -<p>In my experience, the majority of the time you will not find any resources still hanging around. Rather, the namespace will be completely empty. What is going on here?</p> -<p>Let’s take a look at the namespace:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ae81ff">$ kubectl get namespace darn-c101 -o yaml</span> -</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Namespace</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">annotations</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">kubectl.kubernetes.io/last-applied-configuration</span>: <span style="color:#ae81ff">|</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">kubernetes.io/metadata.name</span>: <span style="color:#ae81ff">darn-c101</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">finalizers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">kubernetes</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">status</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">conditions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">lastTransitionTime</span>: <span style="color:#e6db74">&#34;2022-06-01T19:05:31Z&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">message: &#39;Some content in the namespace has finalizers remaining</span>: <span style="color:#ae81ff">darn-c101.geekyryan.io/finalizer in 1 resource instances&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">reason</span>: <span style="color:#ae81ff">SomeFinalizersRemain</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">status</span>: <span style="color:#e6db74">&#34;True&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">NamespaceFinalizersRemaining</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">phase</span>: <span style="color:#ae81ff">Terminating</span> -</span></span></code></pre></div><p>Notice the inclusion of the finalizers field in the above JSON. Some namespaces have a finalizer defined under spec.</p> -<p>A finalizer is a special metadata key that tells Kubernetes to wait until a specific condition is met before it fully deletes a resource. Much like a finalizer in the .NET framework (does Java have those too? 😀 )</p> -<p>So when you run a command like <code>kubectl delete namespace &lt;namespace&gt;</code>, Kubernetes checks for a finalizer in the <code>metadata.finalizers</code> field. If the resource defined in the finalizer cannot be deleted, then the namespace is not deleted either. This puts the namespace into a perpetual terminating state and is never actually deleted.</p> -<p>When an object has been terminating for an excessive time, check its finalizers by inspecting the <code>metadata.finalizers</code> field in its YAML.</p> -<p>So we now know what the problem is. How can we solve it? Well, it’s actually quite simple. If you are using bash, use this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> -</span></span><span style="display:flex;"><span>namespaces<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>kubectl get ns --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Terminating -o jsonpath<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;{range .items[*]}{.metadata.name}{&#34;\n&#34;}{end}&#39;</span><span style="color:#66d9ef">)</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -z <span style="color:#e6db74">&#34;</span>$namespaces<span style="color:#e6db74">&#34;</span><span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">&#34;No namespaces to delete.&#34;</span> -</span></span><span style="display:flex;"><span> exit -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> namespace in $namespaces -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">do</span> -</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">&#34;[Removing Namespace]: </span>$namespace<span style="color:#e6db74">&#34;</span> -</span></span><span style="display:flex;"><span> kubectl get namespace $namespace -o json | tr -d <span style="color:#e6db74">&#34;\n&#34;</span> | sed <span style="color:#e6db74">&#34;s/\&#34;finalizers\&#34;: \[[^]]\+\]/\&#34;finalizers\&#34;: []/&#34;</span> | kubectl replace --raw /api/v1/namespaces/$namespace/finalize -f - &gt; /dev/null 2&gt;&amp;<span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">done</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span> -</span></span></code></pre></div><p><a href="https://gist.github.com/rnemeth90/e83bb4c8808f0d28412cb40edb2487d3">Delete Terminating Kubernetes Namespaces with Bash (github.com)</a></p> -<p>It will search for any namespace that is stuck in the terminating state and forcefully remove it by removing the finalizers field and then using <code> kubectl replace</code> to commit the change back to the Kube API.</p> -<p>If you prefer Powershell, you can use this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$terminatingNamespaces = kubectl get ns --field-selector=status.phase==Terminating -o jsonpath=<span style="color:#e6db74">&#34;{range .items[*]}{.metadata.name}{&#39;\n&#39;}{end}&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($ns <span style="color:#66d9ef">in</span> $terminatingNamespaces) { -</span></span><span style="display:flex;"><span> Write-Verbose <span style="color:#e6db74">&#39;[FOUND]: Forcefully removing $ns&#39;</span> -</span></span><span style="display:flex;"><span> $jsonObj = kubectl get namespace $ns -o json | ConvertFrom-Json | foreach-object { $_.spec.finalizers = @(); $_ } | -</span></span><span style="display:flex;"><span> convertto-json | kubectl replace --raw /api/v1/namespaces/$namespace/finalize <span style="color:#f92672">-f</span> - -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><a href="https://gist.github.com/rnemeth90/19d7de622a5009c1cf908c5d4deb5358">Delete Terminating Kubernetes Namespaces with Powershell (github.com)</a></p> -<p>It does the same thing as the bash script, just in more of a Window-zy way.</p> -<p>It’s that simple. I hope this was helpful. If you have any questions, comments, or concerns, please feel free to reach out.</p> - + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state. A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. - Kubernetes Storage Simplified - https://rnemeth90.github.io/posts/2022-03-01-kubernetes-storage-simplified/ + http://localhost:1313/posts/2022-03-01-kubernetes-storage-simplified/ Tue, 01 Mar 2022 08:37:58 +0000 - - https://rnemeth90.github.io/posts/2022-03-01-kubernetes-storage-simplified/ - <p>In this blog post, we will attempt to explain the current storage options that exist in Kubernetes. If you are new to Kubernetes, learning about its capabilities of managing the application state can be a daunting task.</p> -<p>Container images are built-in layers, with the runtime layer being writable. However, any files on this writable layer are only available for the container’s lifetime. We can mount a volume to a directory inside the container to have persistent data.</p> -<p>Kubernetes storage uses the concepts of volumes. Ephemeral volumes are called volumes and only last the lifetime of a pod, and “persistent volumes” are used for long-term storage. A typical use case for Ephemeral volumes is storing logs that are not sent to stdout.</p> -<p>Mounting a persistent volume inside a container allows you to persist the state of your application long after the container is terminated. Persistent volumes can also take advantage of the typical storage idiosyncrasies such as backup, compression, and encryption.</p> -<h2 id="persistent-volumes" >Persistent Volumes -<span> - <a href="#persistent-volumes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Kubernetes has several types of persistent volumes. At its core, a persistent volume is simply a directory mounted inside a pod. How that volume is created, the configuration options and the medium that backs it are all determined by the type of volume created.</p> -<p>There are several types of volumes available, too many to list here. You may commonly see some volume types: NFS, iSCSI, hostpath, and local. If your Kubernetes cluster exists in a cloud environment such as Azure or AWS, other volume types are available to you (azureDisk, azureFile, and awsElasticBlockStore, respectively). A complete list of types can be found here:</p> -<p><a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes">https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes</a></p> -<p>Creating a persistent volume is generally a simple task. The first step is determining the type of volume to create. In this post, we will cover creating a local volume. A local volume represents a disk, partition, or directory shared from a node. Local volumes are subject to the availability of the underlying node, meaning that if the node is offline, the volume is also offline and will not be accessible by any pod. Because of this, local volumes should not be used in production.</p> -<p>A persistent volume can only be created using a declarative approach. To create a persistent local volume, use the following YAML definition:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolume</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">example-pv</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">capacity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMode</span>: <span style="color:#ae81ff">Filesystem</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteOnce</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeReclaimPolicy</span>: <span style="color:#ae81ff">Delete</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">local-storage</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">local</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># the path to the volume or directory on the node</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/mnt/disks/ssd1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeAffinity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">required</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeSelectorTerms</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">matchExpressions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">key</span>: <span style="color:#ae81ff">kubernetes.io/hostname</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">operator</span>: <span style="color:#ae81ff">In</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">values</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># name of the node sharing the volume</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">node01</span> -</span></span></code></pre></div><p>When creating a persistent volume of this type, you must specify a node affinity. This ensures that the Kubernetes scheduler schedules any pods requesting access to this volume on the correct node. For example, any pod requesting access to the persistent volume named ‘example-PV will only be scheduled on the node ‘node01’.</p> -<p>Let’s dive into this persistent volume spec a bit more:</p> -<p>You can change the capacity of the persistent volume by updating:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">capacity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span></code></pre></div><p>The accessModes will be determined by the storage provider being used. There are generally 3 access modes available: ReadWriteOnce, ReadWriteMany, and ReadOnlyMany.</p> -<ul> -<li>ReadWriteOnce – The volume can be mounted as read-write by a single node</li> -<li>ReadWriteMany – The volume can be mounted as read-write by many nodes</li> -<li>ReadOnlyMany – The volume can be mounted as read-only by many nodes</li> -</ul> -<p>The “persistentVolumeReclaim” policy determines what happens to a persistent volume when it is no longer mounted by any pods (i.e., there are no claims to it, more on this later). There are three options available for the reclaim policy:</p> -<ul> -<li>Retain – The persistent volume is kept as-is. It must be manually removed when no longer needed.</li> -<li>Recycle – The persistent volume is scrubbed and can be re-used by other pods</li> -<li>Delete – The persistent volume is deleted.</li> -</ul> -<p>Currently, only NFS and hostPath volumes support recycling. Cloud storage providers (Azure, AWS, and GCE) support deletion.</p> -<p>The other aspects of this spec are unique to the volume being used. Since we are using a local volume here, we must specify the path to the directory or volume on the host and the host which is sharing the directory or volume:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span> <span style="color:#f92672">local</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># the path to the volume or directory on the node</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/mnt/disks/ssd1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeAffinity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">required</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeSelectorTerms</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">matchExpressions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">key</span>: <span style="color:#ae81ff">kubernetes.io/hostname</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">operator</span>: <span style="color:#ae81ff">In</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">values</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># name of the node sharing the volume</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">node01</span> -</span></span></code></pre></div><h2 id="ephemeral-volumes" >Ephemeral Volumes -<span> - <a href="#ephemeral-volumes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Note: The Kubernetes documentation recognizes configMaps and Secrets as ephemeral volumes. However, in this article, we will only discuss ephemeral volumes used for data storage (emptyDir volumes).</p> -<p>Ephemeral volumes are defined within the context of a pod. This means that you cannot create an ephemeral volume on its own. Instead, define the ephemeral volume in the pod or a deployment spec.</p> -<p>Ephemeral volumes are useful in a few scenarios:</p> -<ol> -<li>You want to share data between multiple containers in a pod</li> -<li>You want to cache temporary information such as log files</li> -<li>You need scratch space to store data before it is processed by another container or pod</li> -</ol> -<p>If one of the containers in the pod happens to restart, data on the ephemeral volume will still exist; as long as one of the containers is mounting, it stays online. In other words, if a pod mounting the ephemeral volume is removed from a node, data on the ephemeral volume is lost. However, if a pod crashes, the data on the volume remains intact.</p> -<p>As stated previously, creating an ephemeral volume is done as part of the pod or deployment template:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/cache</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">emptyDir</span>: {} -</span></span></code></pre></div><p>If the template, you add a volume of type ’emptyDir’ in the ‘volumes’ spec and name it. You can mount this volume in any container in the pod. The volume does not have to be mounted to the same directory in each container.</p> -<h2 id="persistent-volume-claims" >Persistent Volume Claims -<span> - <a href="#persistent-volume-claims"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>A persistentVolumeClaim (often referred to as a ‘PVC’) is used by a pod to create a ‘claim’ on storage. Using a PVC, a pod can mount multiple persistent volumes simultaneously to any directory in the pod.</p> -<p>PersistentVolumeClaim’s are a Kubernetes primitive that can be deployed from a manifest:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fast-storage-pvc</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMode</span>: <span style="color:#ae81ff">Filesystem</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">8Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">fast</span> -</span></span></code></pre></div><p>Most of the options in the manifest above seem pretty obvious. The volumeMode specifies whether to consume the persistent volume as a FileSystem or block device. The resources section helps specify the amount of storage you require (8Gi in this example). We will cover the storageClassName in the next section. Finally, the accessModes are identical to those described above in the Persistent Volumes section.</p> -<p>Pods access a volume by using the persistentVolumeClaim as volume. Claims must exist in the same namespace as the pod using the claim. The controller finds the claim in the pods’ namespace and uses it to find a persistent volume capable of backing the claim. The volume is then mounted on the host and attached to the pod.</p> -<p>To create a pod that utilizes a PVC, use the following yaml definition:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/mnt/share</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span></code></pre></div><h2 id="storage-classes" >Storage Classes -<span> - <a href="#storage-classes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>In this article, we will only be referencing Kubernetes storage classes with respect to dynamic provisioners. If you would like to learn more, please reference the Kubernetes docs:</p> -<p><a href="https://bit.ly/3ruJD2A">https://bit.ly/3ruJD2A</a></p> -<p>Storage Classes have many uses. Kubernetes is unopinionated about what a storage class represents. They can be used to represent different characteristics of storage (performance, compression method, file system modes, etc.). Storage Classes can also be used to provision persistent volumes dynamically, which will be the focus of this article.</p> -<p>Storage classes are often packaged with CSI drivers. Each StorageClass contains the fields “provisioner”, “parameters”, and “reclaimPolicy”. The provisioner field is used to determine what CSI driver is used for provisioning volumes.</p> -<p>This is an example of the storage class packaged with the AzureFiles CSI driver:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">StorageClass</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">storage.k8s.io/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azurefileshare</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">provisioner</span>: <span style="color:#ae81ff">file.csi.azure.com</span> <span style="color:#75715e"># replace with &#34;kubernetes.io/azure-file&#34; if aks version is less than 1.21</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">mountOptions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">dir_mode=0777</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">file_mode=0777</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">uid=0</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">gid=0</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">mfsymlinks</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">cache=strict</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">actimeo=30</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">parameters</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">skuName</span>: <span style="color:#ae81ff">Standard_LRS</span> -</span></span></code></pre></div><p>You can see in the above manifest that the provisioner is set to ‘file.csi.azure.com.’ When a pod uses a PVC in its manifest that references this storage class, the provisioner will dynamically manage the underlying storage.</p> -<p>The name of the storageClass is referenced in the persistentVolumeClaim:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">8Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">azurefileshare</span> -</span></span></code></pre></div><p>You could then reference this PVC in a pod:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/mnt/share</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span></code></pre></div><p>That concludes this article. I know that is a lot of information! As always, if you have any questions or comments, please reach out.</p> - + http://localhost:1313/posts/2022-03-01-kubernetes-storage-simplified/ + In this blog post, we will attempt to explain the current storage options that exist in Kubernetes. If you are new to Kubernetes, learning about its capabilities of managing the application state can be a daunting task. Container images are built-in layers, with the runtime layer being writable. However, any files on this writable layer are only available for the container’s lifetime. We can mount a volume to a directory inside the container to have persistent data. - Kubernetes Pod Eviction - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ Sat, 05 Feb 2022 23:49:16 +0000 - - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ - <p>In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation.</p> -<h2 id="what-is-pod-eviction" >What is Pod Eviction? -<span> - <a href="#what-is-pod-eviction"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. The most common of which is resource starvation on a node. This is referred to as “node-pressure eviction.”</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>NAME READY STATUS RESTARTS AGE -</span></span><span style="display:flex;"><span>nginx 0/1 Evicted <span style="color:#ae81ff">0</span> 10s -</span></span></code></pre></div><h2 id="eviction-process" >Eviction Process -<span> - <a href="#eviction-process"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The kubelet process running on the node monitors resources such as CPU, memory, disk space, inodes, etc. When one of these resources reaches a certain consumption level, the kubelet will first attempt to clean up resources by deleting non-running pods and images (in the case of storage starvation). The kubelet will then fail one or more pods on the node to reclaim resources. The class of the pod determines the order in which it does this.</p> -<p><strong>Pod Classes</strong></p> -<ul> -<li>Guaranteed: Pods that have requests and limits configured for both CPU and memory</li> -<li>Burstable: Pods with a resource request configured for memory or CPU</li> -<li>Best Effort: Pods without any requests or limits</li> -</ul> -<p>The kubelet will first evict any “best-effort” pods. If this is not enough, the kubelet will evict any “burstable” pods. Pods within the “guaranteed” class are theoretically safe from eviction.</p> -<p>During a node-pressure eviction, the kubelet sets the PodPhase for the selected pods to “Failed.” This causes the pods to terminate. If a daemonSet or replicaSet manages the pod, the Kubernetes controller-manager will create new pods on another node.</p> -<h2 id="recovery" >Recovery -<span> - <a href="#recovery"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Node-pressure eviction is almost always avoidable. We can prevent this type of issue by ensuring that we properly size our clusters and create resource limits for pods.</p> -<p><strong>Resource</strong> <strong>Requests and Limits:</strong></p> -<ul> -<li>Requests: The minimum amount of resources (CPU/memory) that a container needs to start.</li> -<li>Limits: The maximum amount of resources that a container is allowed to use.</li> -</ul> -<p>Pod resources and requests can be defined in a pod spec or deployment spec. Below is an example of a pod spec with resource requests and limits defined:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">frontend</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">nginx</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;64Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;250m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">limits</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;128Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;500m&#34;</span> -</span></span></code></pre></div><p>You will often need to clean up evicted pods manually. If you find that your cluster has a large amount of evicted pods, you can clean them up with the following kubectl commands:</p> -<p><strong>To see all failed pods in the cluster:</strong></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl get pod --all-namespaces --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Failed -</span></span></code></pre></div><p><strong>To remove all failed pods in the cluster:</strong></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl delete pod --all-namespaces --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Failed -</span></span></code></pre></div><p>I hope this article has been helpful. Please reach out if you have any questions or comments! Also, if you would like to learn more, take a look at the official Kubernetes docs:</p> -<p><a href="https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/">https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/</a></p> - + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ + In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation. What is Pod Eviction? Link to heading Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. - diff --git a/public/categories/kubernetes/page/1/index.html b/public/categories/kubernetes/page/1/index.html index 5ec89382..f87ebf87 100644 --- a/public/categories/kubernetes/page/1/index.html +++ b/public/categories/kubernetes/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/kubernetes/ - + http://localhost:1313/categories/kubernetes/ + - + diff --git a/public/categories/linux/index.html b/public/categories/linux/index.html new file mode 100644 index 00000000..8207f1ea --- /dev/null +++ b/public/categories/linux/index.html @@ -0,0 +1,234 @@ + + + + + Category: Linux · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + +
    + + + +
    + +
    +
    +

    + Category: Linux +

    +
    + + + + + + + + + +
    + + +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/categories/linux/index.xml b/public/categories/linux/index.xml new file mode 100644 index 00000000..cad1c9f6 --- /dev/null +++ b/public/categories/linux/index.xml @@ -0,0 +1,19 @@ + + + + Linux on GeekyRyan + http://localhost:1313/categories/linux/ + Recent content in Linux on GeekyRyan + Hugo + en + Mon, 27 Nov 2023 00:00:00 +0000 + + + Exploring Netcat + http://localhost:1313/posts/2023-11-27-netcat/ + Mon, 27 Nov 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-11-27-netcat/ + Introduction Link to heading Netcat is a versatile networking utility that can be used for a wide range of tasks. It has often been referred to as the &ldquo;network swiss-army knife&rdquo;. Netcat was first released in the mid-90s, and I personally find it ironic to be blogging about it in 2023! But I feel like it is a somewhat cryptic tool, and new engineers or college graduates may not be familiar. + + + diff --git a/public/categories/linux/page/1/index.html b/public/categories/linux/page/1/index.html new file mode 100644 index 00000000..15ff567b --- /dev/null +++ b/public/categories/linux/page/1/index.html @@ -0,0 +1,10 @@ + + + + http://localhost:1313/categories/linux/ + + + + + + diff --git a/public/categories/netcat/index.html b/public/categories/netcat/index.html new file mode 100644 index 00000000..fc4cf9c0 --- /dev/null +++ b/public/categories/netcat/index.html @@ -0,0 +1,234 @@ + + + + + Category: Netcat · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + +
    + + + +
    + +
    +
    +

    + Category: Netcat +

    +
    + + + + + + + + + +
    + + +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/categories/netcat/index.xml b/public/categories/netcat/index.xml new file mode 100644 index 00000000..bec45b21 --- /dev/null +++ b/public/categories/netcat/index.xml @@ -0,0 +1,19 @@ + + + + Netcat on GeekyRyan + http://localhost:1313/categories/netcat/ + Recent content in Netcat on GeekyRyan + Hugo + en + Mon, 27 Nov 2023 00:00:00 +0000 + + + Exploring Netcat + http://localhost:1313/posts/2023-11-27-netcat/ + Mon, 27 Nov 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-11-27-netcat/ + Introduction Link to heading Netcat is a versatile networking utility that can be used for a wide range of tasks. It has often been referred to as the &ldquo;network swiss-army knife&rdquo;. Netcat was first released in the mid-90s, and I personally find it ironic to be blogging about it in 2023! But I feel like it is a somewhat cryptic tool, and new engineers or college graduates may not be familiar. + + + diff --git a/public/categories/netcat/page/1/index.html b/public/categories/netcat/page/1/index.html new file mode 100644 index 00000000..d653a63b --- /dev/null +++ b/public/categories/netcat/page/1/index.html @@ -0,0 +1,10 @@ + + + + http://localhost:1313/categories/netcat/ + + + + + + diff --git a/public/categories/networking/index.html b/public/categories/networking/index.html index 31d42f49..8aeb8c9c 100644 --- a/public/categories/networking/index.html +++ b/public/categories/networking/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: Networking · GeekyRyan + - - -Networking - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,283 +79,161 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - -
    -
    - -

    Category: Networking

    - - - -
    -
    -
    -

    Layer 2 Switching Fundamentals

    -
    -
    +
    +
    + © -
    - Switches are devices that support a large number of ports to connect devices to the network. -Design: More towards a CCNP or CCDA topic, but designing a network when it comes to the switching side can be done in three building blocks. The access layer, the distribution layer, and the core layer. The access layer generally has a high port density, can support VLANs, QoS, and access lists. The distribution layer will aggregate multiple access layer switches. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2012-11-16-layer-2-switching-fundamentals/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - - + + diff --git a/public/categories/networking/index.xml b/public/categories/networking/index.xml index f65ece6f..9c2a57d5 100644 --- a/public/categories/networking/index.xml +++ b/public/categories/networking/index.xml @@ -2,41 +2,25 @@ Networking on GeekyRyan - https://rnemeth90.github.io/categories/networking/ - GeekyRyan (Networking) - Hugo -- gohugo.io - en-us - Fri, 16 Nov 2012 21:26:00 +0000 - - - - + http://localhost:1313/categories/networking/ + Recent content in Networking on GeekyRyan + Hugo + en + Mon, 27 Nov 2023 00:00:00 +0000 + + + Exploring Netcat + http://localhost:1313/posts/2023-11-27-netcat/ + Mon, 27 Nov 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-11-27-netcat/ + Introduction Link to heading Netcat is a versatile networking utility that can be used for a wide range of tasks. It has often been referred to as the &ldquo;network swiss-army knife&rdquo;. Netcat was first released in the mid-90s, and I personally find it ironic to be blogging about it in 2023! But I feel like it is a somewhat cryptic tool, and new engineers or college graduates may not be familiar. + Layer 2 Switching Fundamentals - https://rnemeth90.github.io/posts/2012-11-16-layer-2-switching-fundamentals/ + http://localhost:1313/posts/2012-11-16-layer-2-switching-fundamentals/ Fri, 16 Nov 2012 21:26:00 +0000 - - https://rnemeth90.github.io/posts/2012-11-16-layer-2-switching-fundamentals/ - <p>Switches are devices that support a large number of ports to connect devices to the network.</p> -<h3 id="design" >Design: -<span> - <a href="#design"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h3><p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h22_54.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h22_54.png" alt=""></a></p> -<p>More towards a CCNP or CCDA topic, but designing a network when it comes to the switching side can be done in three building blocks. The access layer, the distribution layer, and the core layer. The access layer generally has a high port density, can support VLANs, QoS, and access lists. The distribution layer will aggregate multiple access layer switches. These are also generally Layer 3 switches to allow routing among an enterprise. It will need to be able to handle the volume of traffic in addition to supporting the same features as the access layer switches. The core layer is the device which will need the highest bandwidth backplane to deal with all of the traffic.</p> -<h3 id="how-switches-handle-traffic" >How switches handle traffic: -<span> - <a href="#how-switches-handle-traffic"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h3><p>A switch is an intelligent device that can make some decisions on how to handle the data it is given. Switches can be divided into two categories for these decisions: Layer 2 or Layer 3 switches. For the CCNA we will only be interested in the layer 2 switches. Layer 2 switches operate at the data link layer. This layer deals primarily with MAC addresses. A Layer 2 switch will build a CAM table full of dynamically learned MAC addresses. The way it learns these addresses is by inspecting the layer 2 header/trailer and learning the source MAC addresses on the frames it receives. A frame is what a packet is encapsulated in when it moves from device to device across the network.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h23_04.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h23_04.png" alt=""></a></p> -<p>With this example the switch has learned PC1/PC2/and PC3′s MAC addresses. If a packet came in on Fa0/4 from PC4, the switch would look at the source MAC address and put an entry for 4444.4444.4444 on Fa0/4. A switch will route traffic based on this table. There are a few decisions it must make to determine how to handle traffic. When it first receives a frame it will consult it’s CAM table to determine whether or not it has the source MAC address listed for that port. If not, it will add it to the CAM table. In the example above, PC1 sent a frame to the switch, the switch noticed PC1′s MAC address was not in it’s table and added it. The next thing it looks at is the destination MAC address. The CAM table is again consulted. If it finds a match the switch will send the frame directly to the recipient it needs to on whatever port it is on. In the example above, PC1 sends a frame to PC3. Because the switch sees 1111.1111.1111 sending to 3333.3333.3333 and has an entry for 3333.3333.3333 it will send the frame out of port Fa0/3 to the recipient. If a destination is not in the CAM table the switch will need to try to find the recipient. In this case the switch will decide to broadcast the frame out of every port EXCEPT the one it came in on. In this example, PC1 sends a frame destined for PC4. The switch will see a frame from 1111.1111.1111 to 4444.4444.4444. PC4′s MAC address is not in it’s table. The switch will then send the frame out of every port except for Fa0/1 (the source). When PC2 and PC3 get this frame, it will determine if the frame was meant for it, and if not it will ignore it. PC4 will also make the same decision and PC4 will respond. Once PC4 has responded the switch will be able to add PC4′s MAC address to it’s table on Fa0/4.</p> - + http://localhost:1313/posts/2012-11-16-layer-2-switching-fundamentals/ + Switches are devices that support a large number of ports to connect devices to the network. Design: Link to heading More towards a CCNP or CCDA topic, but designing a network when it comes to the switching side can be done in three building blocks. The access layer, the distribution layer, and the core layer. The access layer generally has a high port density, can support VLANs, QoS, and access lists. - diff --git a/public/categories/networking/page/1/index.html b/public/categories/networking/page/1/index.html index cb9d3ca9..c5ddea13 100644 --- a/public/categories/networking/page/1/index.html +++ b/public/categories/networking/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/networking/ - + http://localhost:1313/categories/networking/ + - + diff --git a/public/categories/nginx/index.html b/public/categories/nginx/index.html new file mode 100644 index 00000000..677241e6 --- /dev/null +++ b/public/categories/nginx/index.html @@ -0,0 +1,234 @@ + + + + + Category: Nginx · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + +
    + + + +
    + +
    +
    +

    + Category: Nginx +

    +
    + + + + + + + + + +
    + + +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/categories/nginx/index.xml b/public/categories/nginx/index.xml new file mode 100644 index 00000000..d700d42f --- /dev/null +++ b/public/categories/nginx/index.xml @@ -0,0 +1,19 @@ + + + + Nginx on GeekyRyan + http://localhost:1313/categories/nginx/ + Recent content in Nginx on GeekyRyan + Hugo + en + Mon, 11 Dec 2023 00:00:00 +0000 + + + Nginx Ingress Response Header Size - A Cautionary Tale + http://localhost:1313/posts/2023-12-04-nginx-ingress-resp-header-size/ + Mon, 11 Dec 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-12-04-nginx-ingress-resp-header-size/ + This will be a short post about a recent issue I encountered when using Nginx as a Kubernetes ingress. Though, this could also be encountered when using Nginx as a reverse proxy as well. The two definitions are functionally similar. We recently had a client call in complaining of our application returning random 502s (Bad Gateway). After some investigation and the common finger-pointing, I found this entry in the logs of our ingress controllers: + + + diff --git a/public/categories/nginx/page/1/index.html b/public/categories/nginx/page/1/index.html new file mode 100644 index 00000000..2f9ddd8b --- /dev/null +++ b/public/categories/nginx/page/1/index.html @@ -0,0 +1,10 @@ + + + + http://localhost:1313/categories/nginx/ + + + + + + diff --git a/public/categories/powershell/index.html b/public/categories/powershell/index.html index 313d7740..6b19c0ad 100644 --- a/public/categories/powershell/index.html +++ b/public/categories/powershell/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: PowerShell · GeekyRyan + - - -Powershell - GeekyRyan - - - - - - - - - - + - - + + + - - + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,368 +79,161 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    -
    -
    - -

    Category: Powershell

    - + 2023-08-15 + Using try/catch/finally Blocks in PowerShell + +
  • + 2022-08-04 + Powershell for Devops - Querying REST APIs with Powershell +
  • -
    -
    -
    -

    Using try/catch/finally Blocks in PowerShell

    -
    - -
    + + - -
    - Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it’s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we’ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn’t crash when the unexpected occurs. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Powershell for Devops - Querying REST APIs with Powershell

    -
    -
    +
    +
    + © -
    - This will be a short post on querying REST APIs with Powershell. -It’s hard to argue that REST APIs are the predominant technology for interacting with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) product without having to go through the exercise of a more complicated integration. REST APIs communicate in a common format, typically JSON. However, most will allow us to choose the response format by specifying an option in the ‘Accept’ header. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - +
    +
    -
    - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - - + + diff --git a/public/categories/powershell/index.xml b/public/categories/powershell/index.xml index c49def31..dcbe7a9b 100644 --- a/public/categories/powershell/index.xml +++ b/public/categories/powershell/index.xml @@ -1,195 +1,26 @@ - Powershell on GeekyRyan - https://rnemeth90.github.io/categories/powershell/ - GeekyRyan (Powershell) - Hugo -- gohugo.io - en-us + PowerShell on GeekyRyan + http://localhost:1313/categories/powershell/ + Recent content in PowerShell on GeekyRyan + Hugo + en Tue, 15 Aug 2023 00:00:00 +0000 - - - - + Using try/catch/finally Blocks in PowerShell - https://rnemeth90.github.io/posts/2023-08-15-powershell-try-catch/ + http://localhost:1313/posts/2023-08-15-powershell-try-catch/ Tue, 15 Aug 2023 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2023-08-15-powershell-try-catch/ - <p>Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it&rsquo;s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we&rsquo;ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn&rsquo;t crash when the unexpected occurs. We&rsquo;ll then cover the differences in terminating and non-terminating errors and why you should take these into consideration when implementing error handling.</p> -<h2 id="the-try-block" >The Try Block -<span> - <a href="#the-try-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The Try block is where you place the code that might generate an error. Think of it as a protective bubble around your potentially troublesome code. If an error occurs within the Try block, PowerShell will immediately jump to the corresponding Catch block.</p> -<p>Here&rsquo;s a simple example:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><h2 id="the-catch-block" >The Catch Block -<span> - <a href="#the-catch-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The Catch block is where you can handle the error. PowerShell provides you with a special variable $_ that contains information about the error. You can use this variable to display error messages or even take corrective actions.</p> -<p>In the example above, we&rsquo;re capturing the error generated by attempting to retrieve a nonexistent file. The $_ variable holds the error message, which we&rsquo;re displaying using Write-Host.</p> -<h2 id="the-finally-block" >The Finally Block -<span> - <a href="#the-finally-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Now, let&rsquo;s talk about the unsung hero – the Finally block. This block is executed regardless of whether an error occurred or not. It&rsquo;s where you can place cleanup code that ensures your script leaves no trace behind, even in the face of adversity. Some tasks that are commonly done in the finally block are closing database connections, removing temp files, etc. The finally block is completely optional.</p> -<pre tabindex="0"><code> -try { - # Code that might generate an error - # ... -} -catch { - # Code to handle the error - # ... -} -finally { - # Cleanup code here - # ... -} -</code></pre><h2 id="terminatingnon-terminating-errors" >Terminating/non-terminating Errors -<span> - <a href="#terminatingnon-terminating-errors"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>non-terminating errors are any error that will not stop the execution of your script. Most cmdlets in PowerShell are non-terminating. They may output an error, but your script will continue to run. These kinds of errors cannot be caught with a catch block by default. The reason for this is the default <code>ErrorAction</code> in your PowerShell profile, which is set to <code>Continue</code>.</p> -<pre tabindex="0"><code># To show your default error action type -$ErrorActionPreference -</code></pre><p>Let&rsquo;s go back and look at our first example:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><p>If you took the time to run this code, you may have noticed that the <code>Write-Host</code> cmdlet in the <code>catch</code> block was never ran. Why did we get a red error message in our PowerShell console, rather than the text <code>An error occurred: ...</code>? The reason is that the non-existing path isn&rsquo;t a terminating error, and the default <code>ErrorAction</code> is <code>Continue</code>. To catch the error, you will need to change the <code>ErrorAction</code> in your PowerShell console to <code>Stop</code>. This can be done in multiple ways. You can add <code>-ErrorAction Stop</code> to the cmdlet, like this:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -ErrorAction Stop -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><p>Or you can change the <code>ErrorActionPreference</code> for the entire script, by adding this to the top of the script:</p> -<pre tabindex="0"><code>$ErrorActionPreference = &#34;Stop&#34; -</code></pre><h2 id="exceptions" >Exceptions -<span> - <a href="#exceptions"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>If you have ever worked with exceptions in C# you can skip this section. In the previous examples, we used simple <code>catch</code> blocks that will catch <em>any</em> error. This is a good start, but we can do better. PowerShell allows you to catch individual exceptions based on the exception type, similar to how C# handles catching exceptions.</p> -<p>Let&rsquo;s look at an example:</p> -<pre tabindex="0"><code>try { - # Attempt to open a non-existent file - $file = Get-Content -Path &#34;NonexistentFile.txt&#34; -} -catch [System.IO.FileNotFoundException] { - Write-Host &#34;Caught a FileNotFoundException: $_&#34; -} -catch { - Write-Host &#34;Caught an exception: $_&#34; -} -</code></pre><p>We now have two <code>catch</code> blocks. If we encounter an exception of type <code>System.IO.FileNotFoundException</code>, the first <code>catch</code> block will catch the exception and handle it accordingly. The second <code>catch</code> block will handle any other generic error.</p> -<h2 id="conclusion" >Conclusion -<span> - <a href="#conclusion"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Error handling might seem daunting at first, but with the power of Try-Catch-Finally blocks at your fingertips, you&rsquo;re well-equipped to handle errors gracefully and ensure the resilience of your PowerShell scripts. Remember, every error is an opportunity to refine your skills and make your scripts more robust.</p> -<p>Thanks for reading!</p> -<p>Official Microsoft Documentation for Try-Catch-Finally in PowerShell: -<a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-7.3">about_try_catch_finally</a></p> - + http://localhost:1313/posts/2023-08-15-powershell-try-catch/ + Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it&rsquo;s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we&rsquo;ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn&rsquo;t crash when the unexpected occurs. - Powershell for Devops - Querying REST APIs with Powershell - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ Thu, 04 Aug 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ - <p>This will be a short post on querying REST APIs with Powershell.</p> -<p>It&rsquo;s hard to argue that REST APIs are the predominant technology for interacting -with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) -product without having to go through the exercise of a more complicated integration. REST APIs communicate -in a common format, typically JSON. However, most will allow us to choose the response format by specifying an -option in the &lsquo;Accept&rsquo; header. Most languages provide a native method for interacting with -REST APIs. This objective for this post is to show you how simple this is with Powershell.</p> -<p>To get started, we&rsquo;ll need a public API to interact with. I&rsquo;m going to use <a href="https://icanhazdadjoke.com/">https://icanhazdadjoke.com/</a>, because -there is no authentication and no rate-limiting (two concepts we will cover in another post).</p> -<p>Calling the API is extremely simple:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -</span></span></code></pre></div><p>However, this results in the content being returned as plain text. This isn&rsquo;t ideal.</p> -<p>Let&rsquo;s pass the &lsquo;Accept&rsquo; header to tell the API the format we are expecting to be returned:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers -</span></span></code></pre></div><p>Output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>[<span style="color:#ae81ff">15</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">04</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">34</span>] C:\..\..\rnemeth90.github.io on <span style="color:#960050;background-color:#1e0010"></span>main <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#ae81ff">+1</span> <span style="color:#960050;background-color:#1e0010">❯</span> Invoke-RestMethod -Uri $url -Method Get -Headers $headers -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>id joke status -</span></span><span style="display:flex;"><span>-- ---- ------ -</span></span><span style="display:flex;"><span>3LmyXvsPfqc I don<span style="color:#e6db74">&#39;t trust stairs. They&#39;</span>re always up to something. <span style="color:#ae81ff">200</span> -</span></span></code></pre></div><p>That looks a little better. For those of you familiar with Powershell, the output above probably -looks completely normal. But for those not-so-familiar with Powershell, or those expecting -more of a &lsquo;json-esk&rsquo; output, this may look a bit&hellip; weird.</p> -<p>Powershell is an object oriented language. <strong>Everything is an object</strong> in Powershell, even the response -of this request. What you see in the output is simply the properties of the object.</p> -<p>Luckily Powershell provides us with a cmdlet to convert an object into json (aptly named: ConvertTo-Json). We can use it like this:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers | ConvertTo-Json -</span></span></code></pre></div><p>Here we are piping the output from Invoke-RestMethod to ConvertTo-Json. Pretty neat!</p> -<p>Output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>[<span style="color:#ae81ff">15</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">04</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">35</span>] C:\..\..\rnemeth90.github.io on <span style="color:#960050;background-color:#1e0010"></span>main <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#ae81ff">+1</span> <span style="color:#960050;background-color:#1e0010">❯</span> Invoke-RestMethod -Uri $url -Method Get -Headers $headers | Convertto-json -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;id&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#e6db74">&#34;AAdFBXnGlyd&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;joke&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#e6db74">&#34;If you walk into a forest and cut down a tree, but the tree doesn&#39;t understand why you cut it down, do you think it&#39;s stumped?&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;status&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#ae81ff">200</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Now, that looks more normal.</p> -<p>There is much more we can do with Invoke-RestMethod. The &lsquo;Method&rsquo; parameter of this cmdlet accepts any of the common -HTTP methods (GET, PUT, PATCH, DELETE, POST, HEAD). You can also specify other headers and a body (using the -body parameter).</p> -<p>Both of these parameters accept dictionaries:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Host&#39;</span> = <span style="color:#e6db74">&#39;MyServer&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>$body = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Eat&#39;</span> = <span style="color:#e6db74">&#39;Pizza&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers -Body $body | ConvertTo-Json -</span></span></code></pre></div><p>Unfortunately I won&rsquo;t be able to show the other HTTP methods, as this API only supports GET requests. So that&rsquo;s all for now.</p> - + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ + This will be a short post on querying REST APIs with Powershell. It&rsquo;s hard to argue that REST APIs are the predominant technology for interacting with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) product without having to go through the exercise of a more complicated integration. REST APIs communicate in a common format, typically JSON. However, most will allow us to choose the response format by specifying an option in the &lsquo;Accept&rsquo; header. - diff --git a/public/categories/powershell/page/1/index.html b/public/categories/powershell/page/1/index.html index 817c61ad..fadc4625 100644 --- a/public/categories/powershell/page/1/index.html +++ b/public/categories/powershell/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/powershell/ - + http://localhost:1313/categories/powershell/ + - + diff --git a/public/categories/sftp/index.html b/public/categories/sftp/index.html index da5121fa..061a65b3 100644 --- a/public/categories/sftp/index.html +++ b/public/categories/sftp/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: SFTP · GeekyRyan + - - -sFTP - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,300 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Category: sFTP

    - - - -
    -
    -
    -

    Azure Kubernetes sFTP Solution

    -
    -
    +
    +
    + © -
    - In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault. -Here is the link to my Github account where you can download the code mentioned in this article: -https://github.com/rnemeth90/kubernetes-sftp -We will work through the following steps in this article: -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - - + + diff --git a/public/categories/sftp/index.xml b/public/categories/sftp/index.xml index baac8692..8a382c87 100644 --- a/public/categories/sftp/index.xml +++ b/public/categories/sftp/index.xml @@ -1,198 +1,19 @@ - sFTP on GeekyRyan - https://rnemeth90.github.io/categories/sftp/ - GeekyRyan (sFTP) - Hugo -- gohugo.io - en-us + SFTP on GeekyRyan + http://localhost:1313/categories/sftp/ + Recent content in SFTP on GeekyRyan + Hugo + en Sun, 16 Jan 2022 07:00:00 +0000 - - - - + Azure Kubernetes sFTP Solution - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ + http://localhost:1313/posts/2022-01-16-azure-kubernetes-sftp-solution/ Sun, 16 Jan 2022 07:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ - <p>In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault.</p> -<p>Here is the link to my Github account where you can download the code mentioned in this article:</p> -<p><a href="https://github.com/rnemeth90/kubernetes-sftp">https://github.com/rnemeth90/kubernetes-sftp</a></p> -<p>We will work through the following steps in this article:</p> -<ol> -<li>Deploy the AzureFile CSI driver to the AKS cluster</li> -<li>Create a configMap that our initContainer will</li> -<li>Deploy a persistent volume claim that an Azure File share will back</li> -<li>Deploy a replicaSet consisting of our initContainer and application container</li> -<li>Deploy a service to serve traffic</li> -</ol> -<p>First, you will need to deploy the Azure Files CSI driver to your AKS cluster. AKS uses this daemon set to dynamically provision/destroy Azure NFSv4 File Shares. The Azure Files CSI driver creates a storage account in the node pool resource group, in which it will then provision the file share.</p> -<p>Deploying the Azure Files CSI driver is a simple task. You will need to run this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/install-driver.sh | bash -s master -- -</span></span></code></pre></div><p>You can use the following commands to verify that the daemon set has exists:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl -n kube-system get pod -o wide --watch -l app<span style="color:#f92672">=</span>csi-azurefile-controller -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>kubectl -n kube-system get pod -o wide --watch -l app<span style="color:#f92672">=</span>csi-azurefile-node -</span></span></code></pre></div><figure class="wp-block-coblocks-gallery-masonry masonry-grid has-border-radius-10 has-medium-gutter"><figure class="wp-block-image size-large masonry-brick">[![Image gallery image](https://rnemeth90.github.io/wp-content/uploads/2022/01/image-1-1024x434.png)](https://rnemeth90.github.io/wp-content/uploads/2022/01/image-1.png)</figure></figure>Next, you need to create a storage class by deploying this yaml file: -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl create -f https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/example/storageclass-azurefile-nfs.yaml -</span></span></code></pre></div><p>Read more about the AzureFiles CSI driver at the following Github link:</p> -<p><a href="https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/install-driver-on-aks.md">https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/install-driver-on-aks.md</a></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ConfigMap</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">creationTimestamp</span>: <span style="color:#66d9ef">null</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">testcm</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">init.sh</span>: |-<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> #!/bin/bash -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> CONF_FILE=&#34;/etc/sftp/users.conf&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> KEYVAULT=&#34;Insert name of Key Vault&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_ID=&#34;Insert service principal Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_PASSWORD=&#34;Insert service principal password&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_TENANT_ID=&#34;Insert Az AAD Tenant Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SUBSCRIPTION_ID=&#34;Insert Az Subscription Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az login --service-principal --username &#34;${AZ_SPN_ID}&#34; --password &#34;${AZ_SPN_PASSWORD}&#34; --tenant &#34;${AZ_SPN_TENANT_ID}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az account set --subscription &#34;${AZ_SUBSCRIPTION_ID}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETS+=($(az keyvault secret list --vault-name $KEYVAULT --query &#34;[].id&#34; -o tsv)) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> chmod 755 /home -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [[ -e $CONF_FILE ]]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> rm -rf &#34;${CONF_FILE}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> touch $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> else -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> touch $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> for SECRET in &#34;${SECRETS[@]}&#34;; do -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETNAME=$(basename $SECRET | tr -d &#39;\r&#39;) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETVALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $SECRETNAME --query &#39;value&#39; | tr -d &#39;&#34;&#39; | tr -d &#39;\r&#39;) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;$SECRETNAME:$SECRETVALUE:::upload&#34; &gt;&gt; $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> done -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [[ ! -s $CONF_FILE ]]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;** ERROR: user.conf is empty&#34; 1&gt;&amp;2 -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> exit 1 -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi</span> -</span></span></code></pre></div><p>The initContainer will use this configMap to read secrets from an Azure Key Vault and then write the secrets to the users.conf file. The users.conf file contains user account information. In the Key Vault, the secret name should be the username and the secret value should be the password. This Key Vault must exist and contain the secrets prior to deploying this solution.</p> -<p>When I deployed this solution in my environment, I used an Azure DevOps pipeline to create/manage the Key Vault with Terraform and then deploy the secrets using an inline Powershell script. However, this is beyond the scope of this article, and I will not be covering it here. You will also need to create a Service Principal in your AAD tenant and grant it access to the Key Vault. The Service Principal needs to have at least read access to the Key Vault.</p> -<p>Before deploying the configMap, you need to fill in values for these variables:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span> KEYVAULT<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert name of Key Vault&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert service principal Id&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_PASSWORD<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert service principal password&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_TENANT_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert Az AAD Tenant Id&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SUBSCRIPTION_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert Az Subscription Id&#34;</span> -</span></span></code></pre></div><p>These values pertain to the service principal with read access to the Key Vault. After filling out these variables, you can deploy the configMap using kubectl.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl create -f configmap.yaml -</span></span></code></pre></div><p>You can deploy the PVC using this yaml file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">azurefile-csi-nfs</span> -</span></span></code></pre></div><p>When creating the persistent volume claim for the deployment, you specify azurefile-csi-nfs as the StorageClass. This will create an NFSv4 share in a premium storage account. The reclaim policy of the storage class ensures that the file share is deleted when the associated Persistent Volume is deleted. Change the reclaim policy to “Retain” if you want the file shares to persist after deleting the PV. Furthermore, the storage class enables the file share to be expandable by modifying the storage request size on the PVC.</p> -<p>After deploying the PVC, you can verify its existence by running:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl get pvc -</span></span></code></pre></div><p>You should see output similar to the following (the manifest for the replicaSet is by far the most complicated of all the code referenced here):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Deployment</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">matchLabels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">strategy</span>: {} -</span></span><span style="display:flex;"><span> <span style="color:#f92672">template</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initContainer</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">chmodder</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">mcr.microsoft.com/azure-cli</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">command</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">/bin/sh</span> -</span></span><span style="display:flex;"><span> - -<span style="color:#ae81ff">c</span> -</span></span><span style="display:flex;"><span> - <span style="color:#e6db74">&#34;/scripts/init.sh&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/scripts</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">docker.io/atmoz/sftp:alpine</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">imagePullPolicy</span>: <span style="color:#ae81ff">IfNotPresent</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;64Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;250m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">limits</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;128Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;500m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">livenessProbe</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tcpSocket</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initialDelaySeconds</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">timeoutSeconds</span>: <span style="color:#ae81ff">5</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">periodSeconds</span>: <span style="color:#ae81ff">10</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">failureThreshold</span>: <span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readinessProbe</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tcpSocket</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initialDelaySeconds</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">timeoutSeconds</span>: <span style="color:#ae81ff">5</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">periodSeconds</span>: <span style="color:#ae81ff">10</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">failureThreshold</span>: <span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/home</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/etc/sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">dnsPolicy</span>: <span style="color:#ae81ff">ClusterFirst</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">restartPolicy</span>: <span style="color:#ae81ff">Never</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">configMap</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">emptyDir</span>: {} -</span></span></code></pre></div><p>You may need to change the CPU/memory requests and limits. These values worked for me, but your results may vary. You can also add/change the labels as you see fit.</p> -<p>This will handle routing traffic to our pods.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Service</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp-service</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">LoadBalancer</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">ports</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">protocol</span>: <span style="color:#ae81ff">TCP</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">targetPort</span>: <span style="color:#ae81ff">22</span> -</span></span></code></pre></div><p>Users will be connected in a round-robin fashion to the pods. This manifest will create a service of type LoadBalancer. Which will in turn create a new public Azure Load Balancer in the resource group that contains your Azure Kubernetes Service cluster if one does not already exist. If you already have a public load balancer, a new frontend IP address will be added.</p> -<p>That’s all for now. Please feel free to contact me if you have any questions.</p> - + http://localhost:1313/posts/2022-01-16-azure-kubernetes-sftp-solution/ + In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault. Here is the link to my Github account where you can download the code mentioned in this article: https://github.com/rnemeth90/kubernetes-sftp We will work through the following steps in this article: - diff --git a/public/categories/sftp/page/1/index.html b/public/categories/sftp/page/1/index.html index 26498e59..01c9ec17 100644 --- a/public/categories/sftp/page/1/index.html +++ b/public/categories/sftp/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/sftp/ - + http://localhost:1313/categories/sftp/ + - + diff --git a/public/categories/software-deployment/index.html b/public/categories/software-deployment/index.html index bdd73e36..c08ebd8b 100644 --- a/public/categories/software-deployment/index.html +++ b/public/categories/software-deployment/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: Software Deployment · GeekyRyan + - - -Software Deployment - GeekyRyan - - - + - - - + + + - - + + + + + + + + + - + + + + - - - - - - - - - - - - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,437 +79,166 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - + + + - - - - - - - - -
    -
    - -

    Category: Software Deployment

    - - - -
    -
    -
    -

    Running Docker in WSL v1

    -
    - -
    - - -
    - I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. -Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. -
    - - -
    - Read more -
    - - - +
    + + + +
    +
  • + 2022-01-14 + Continuous Deployment Models +
  • -
    -
    -
    -

    Accessing Secrets Securely in Azure DevOps Pipelines

    -
    - -
    + + - -
    - This post will cover a secure method for accessing secrets in Azure DevOps pipelines. -Why Azure Key Vault? Azure Key Vault is an Azure cloud service used to securely store secrets, keys, and certificates. A secret can be any string of characters, such as API keys, passwords, URLs, etc. Azure Key Vault encrypts data at rest and in transit using HTTPS. Depending on the type of Key Vault you are using, data at rest is encrypted using software encryption (AES 256) or HSM-backed keys. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Continuous Deployment Models

    -
    -
    +
    +
    + © -
    - When deploying new software releases to servers or (insert -as-a-service> here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments. -Blue/Green Deployments Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. Instead, it gets deployed to another set of servers (blue) first. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - +
    +
    +
    -
    - - - - - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - -
    + + diff --git a/public/categories/software-deployment/index.xml b/public/categories/software-deployment/index.xml index 6cdd07dd..7bda6409 100644 --- a/public/categories/software-deployment/index.xml +++ b/public/categories/software-deployment/index.xml @@ -2,197 +2,32 @@ Software Deployment on GeekyRyan - https://rnemeth90.github.io/categories/software-deployment/ - GeekyRyan (Software Deployment) - Hugo -- gohugo.io - en-us + http://localhost:1313/categories/software-deployment/ + Recent content in Software Deployment on GeekyRyan + Hugo + en Sun, 26 Jun 2022 15:00:28 +0000 - - - - + Running Docker in WSL v1 - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ Sun, 26 Jun 2022 15:00:28 +0000 - - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ - <p>I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate.</p> -<p>Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. I receive this nice message:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ docker -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>The command <span style="color:#e6db74">&#39;docker&#39;</span> could not be found in this WSL <span style="color:#ae81ff">1</span> distro. -</span></span><span style="display:flex;"><span>We recommend to convert this distro to WSL <span style="color:#ae81ff">2</span> and activate -</span></span><span style="display:flex;"><span>the WSL integration in Docker Desktop settings. -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>See https://docs.docker.com/docker-for-windows/wsl/ <span style="color:#66d9ef">for</span> details. -</span></span></code></pre></div><p>So I’m in somewhat of a catch-22 here…</p> -<p>To work around this problem until a proper solution is found, I was able to get Docker working with WSL v1.</p> -<p>If you happen to be having a similar issue (and it seems like quite a few people are, considering the number of Github posts I found), just follow these steps:</p> -<ul> -<li>Expose the Docker daemon in docker desktop settings:</li> -</ul> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/02/image-10-1024x585.png"></a></p> -<p>Install the stand-alone Docker client in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ tar zxvf docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ cd docker -</span></span></code></pre></div><p>Set the default Docker daemon in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>export DOCKER_HOST<span style="color:#f92672">=</span>tcp://localhost:2375 -</span></span></code></pre></div><p>Verify you can connect to Docker running on Windows from within WSL:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>./docker info -</span></span></code></pre></div><p>This is also beneficial in that you only have one Docker host to manage your containers, network, etc., rather than two.</p> - + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ + I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. - Accessing Secrets Securely in Azure DevOps Pipelines - https://rnemeth90.github.io/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ + http://localhost:1313/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ Sat, 19 Feb 2022 16:02:50 +0000 - - https://rnemeth90.github.io/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ - <p>This post will cover a secure method for accessing secrets in Azure DevOps pipelines.</p> -<h2 id="why-azure-key-vault" >Why Azure Key Vault? -<span> - <a href="#why-azure-key-vault"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Azure Key Vault is an Azure cloud service used to securely store secrets, keys, and certificates. A secret can be any string of characters, such as API keys, passwords, URLs, etc. Azure Key Vault encrypts data at rest and in transit using HTTPS. Depending on the type of Key Vault you are using, data at rest is encrypted using software encryption (AES 256) or HSM-backed keys.</p> -<p>Azure Key Vault also gives us the ability to control access to secrets, keys, and certificates using native Key Vault access policies or the newer option of Azure IAM (RBAC) integration.</p> -<h2 id="what-are-variable-groups" >What are Variable Groups? -<span> - <a href="#what-are-variable-groups"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>It’s all in the name. Variable groups are simply a method of grouping Azure DevOps pipeline variables. If you created a release for an application named MyAwesomeApp, you could create a variable group named myawesomeapp-var-group that could then store all of the variables you reference in the release. It’s simply a method of organizing variables.</p> -<p>You apply permissions to variable groups so that only certain people and pipelines/releases are able to use them.</p> -<p>You can read more here about variable groups and their usage:</p> -<p><a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/library/variable-groups?view=azure-devops&amp;tabs=yaml#use-a-variable-group">https://docs.microsoft.com/en-us/azure/devops/pipelines/library/variable-groups?view=azure-devops&amp;tabs=yaml#use-a-variable-group</a></p> -<h2 id="creating-a-key-vault-and-adding-secrets" >Creating a Key Vault and Adding Secrets -<span> - <a href="#creating-a-key-vault-and-adding-secrets"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p><strong>If you already have a Key Vault, skip this section.</strong></p> -<p>In this post, we will create a Key Vault using the AzureCLI. To create the Vault and a secret, run these commands:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># Create a resource group</span> -</span></span><span style="display:flex;"><span>az group create --location &lt;location&gt; --name &lt;resource-group-name&gt; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Create a KeyVault</span> -</span></span><span style="display:flex;"><span>az keyvault create --name &lt;keyvault-name&gt; --resource-group &lt;resource-group-name&gt; --enable-soft-delete -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Create some secrets in the Key Vault</span> -</span></span><span style="display:flex;"><span>az keyvault secret set --name username --vault-name &lt;keyvault-name&gt; --value &lt;username&gt; -</span></span><span style="display:flex;"><span>az keyvault secret set --name password --vault-name &lt;keyvault-name&gt; --value &lt;password&gt; -</span></span><span style="display:flex;"><span>az keyvault secret set --name tenantId--vault-name &lt;keyvault-name&gt; --value &lt;tenant id&gt; -</span></span></code></pre></div><p>You will need to update the location and resource group name with whatever values you want. You will also need to update the username, password, and your Azure AD tenant ID. The username you choose will need read access to your subscription.</p> -<h2 id="creating-a-variable-group" >Creating a Variable Group -<span> - <a href="#creating-a-variable-group"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Now we’ll create the variable group in Azure DevOps.</p> -<p>Go to your Azure DevOps project &gt; Pipelines &gt; Library and click “+ Variable Group”:</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image.png"></a></p> -<p>Give your variable group a name. Then toggle the switch “Link secrets from an Azure key vault as variables”. Select your Azure Subscription (you may need to authorize DevOps access to the subscription, and then select the Key Vault.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-1.png"></a></p> -<p>Now we can add the secrets from the Key Vault to the variable group. Under “Variables”, click the “+ Add” button. Select the checkbox next to any secrets you want to add to the variable group, and then click “Ok”.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-7.png"></a></p> -<p>Finally, click the “Save” button. You now have a variable group with secrets linked to a Key Vault. Notice the name of the secret is the only thing visible from the variable group. If you were to update the secret value in the Key Vault, Azure DevOps would automatically pick up the new value.</p> -<h2 id="use-the-variable-group-in-a-pipeline" >Use the Variable Group in a Pipeline -<span> - <a href="#use-the-variable-group-in-a-pipeline"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Now that we have our variable group in place, let’s use it in a pipeline. In Azure DevOps, go to Pipelines and click “New pipeline”.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-8-1024x596.png"></a></p> -<p>Choose “Azure Repos Git” &gt; “&lt; your git repo&gt; “, “Starter Pipeline”, and then paste in the following code (You will need to update the ‘azureSubscription’ field with your SPN):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">variables</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">group</span>: <span style="color:#ae81ff">kv-secrets</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pr</span>: <span style="color:#ae81ff">none</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">stages</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">stage</span>: <span style="color:#ae81ff">print_resource_groups</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">jobs</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">job</span>: <span style="color:#ae81ff">print_resource_groups</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">continueOnError</span>: <span style="color:#66d9ef">false</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">task</span>: <span style="color:#ae81ff">AzureCLI@2</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">inputs</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">azureSubscription</span>: <span style="color:#e6db74">&#39;&lt;Your SPN&gt;&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">scriptType</span>: <span style="color:#e6db74">&#39;bash&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">scriptLocation</span>: <span style="color:#e6db74">&#39;inlineScript&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">inlineScript</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az login --service-principal --username $(username) --password $(password) --tenant $(tenantId) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az group list</span> -</span></span></code></pre></div><p>Now click “Save and Run”, and then “Save and Run” again.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-9-1024x596.png"></a></p> -<p>Once the pipeline finishes running, you can see that it was able to read the subscription and create a list of all resource groups found.</p> -<p>This is a simple example of using Key Vault credentials in a pipeline. But you can imagine how useful this could be in more complex scenarios.</p> -<p>That’s all for now. If you have any questions, feel free to reach out!</p> - + http://localhost:1313/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ + This post will cover a secure method for accessing secrets in Azure DevOps pipelines. Why Azure Key Vault? Link to heading Azure Key Vault is an Azure cloud service used to securely store secrets, keys, and certificates. A secret can be any string of characters, such as API keys, passwords, URLs, etc. Azure Key Vault encrypts data at rest and in transit using HTTPS. Depending on the type of Key Vault you are using, data at rest is encrypted using software encryption (AES 256) or HSM-backed keys. - Continuous Deployment Models - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ + http://localhost:1313/posts/2022-01-14-continuous-deployment-models/ Fri, 14 Jan 2022 19:24:01 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ - <p>When deploying new software releases to servers or (insert -as-a-service&gt; here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments.</p> -<h2 id="bluegreen-deployments" >Blue/Green Deployments -<span> - <a href="#bluegreen-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. Instead, it gets deployed to another set of servers (blue) first. Since the blue servers are not currently serving any traffic for users, the deployment has no impact. However, once the deployment has been completed successfully and tested, users will be directed to the new deployment (blue). You can control all user traffic or a subset of user traffic if your load balancer supports it (referred to as ‘Progressive Exposure’).</p> -<p>The next release will then repeat the same process. Blue would be the current production environment, so you would first deploy to the green servers. This model requires two sets of identical hosts and a load balancer or reverse proxy in front of them. If there are any unexpected issues with the new release, it is straightforward to switch back to the previous release. The disadvantage to this type of model is that it requires having redundant environments (and potentially wasted resources). However, this is less of a concern if using container orchestration platforms such as Kubernetes.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/01/2022-01-19_07h57_58-1024x575.png" alt="Blue Green deployment model"></p> -<h2 id="immutable-servers" >Immutable Servers -<span> - <a href="#immutable-servers"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>There is an alternative method of blue/green deployments called “immutable servers”. This method is identical to blue/green deployments as described above. However, after switching user traffic over to the servers with the new release, the old servers are destroyed. They are not used again. This type of model becomes particularly efficient when using a pipeline that is capable of creating servers for you (i.e., Azure DevOps Pipelines)</p> -<h2 id="canary-deployments" >Canary Deployments -<span> - <a href="#canary-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>In a canary deployment, not all users are routed to the new release immediately. Only a limited percentage of users get access to the new release. These users are the canaries. They should be monitored closely, so it is important to be using Not all users are routed to the new release immediately in a canary deployment. Only a limited percentage of users get access to the latest release. These users are the canaries.</p> -<p>Organizations should monitor the canaries closely, so it is essential to be using monitoring software capable of looking at the statistics of a web application from the users’ perspective (for example, Application Insights). The number of canaries can increase until all traffic is directed to the new release over time. The most significant advantage of this method is limited exposure to issues. If a problem appears after the release is deployed, only a small subset of users will experience it. After you fix the issues and redeploy the release, it’s best to select a different group of users to be canaries.</p> -<h2 id="ring-based-deployments" >Ring Based Deployments -<span> - <a href="#ring-based-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>A ring-based deployment has multiple production environments. Each serves a limited number of users, similar to a canary deployment. However, you can have as many production environments as you want with a ring-based deployment. New releases are deployed to the rings one by one over time.</p> -<h2 id="feature-flag-deployments" >Feature Flag Deployments -<span> - <a href="#feature-flag-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Feature flags are used to expose new features to sets of users slowly. Unlike the other deployment models, they are not implemented in the infrastructure. Instead, they are typically implemented and enabled in code or database. An example would be a feature flag in a database that gives users access to a button on your web page. A developer could enable the flag for a set of users. These users would be able to see the button; other users would not. Feature flags can even toggle bug fixes or performance improvements.</p> -<p>I will cover implementing blue/green deployments in Azure using Azure DevOps and App Services in a future article.</p> - + http://localhost:1313/posts/2022-01-14-continuous-deployment-models/ + When deploying new software releases to servers or (insert -as-a-service&gt; here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments. Blue/Green Deployments Link to heading Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. - diff --git a/public/categories/software-deployment/page/1/index.html b/public/categories/software-deployment/page/1/index.html index 1c6b6d6f..b4698c5b 100644 --- a/public/categories/software-deployment/page/1/index.html +++ b/public/categories/software-deployment/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/software-deployment/ - + http://localhost:1313/categories/software-deployment/ + - + diff --git a/public/categories/software-development/index.html b/public/categories/software-development/index.html index 83d92fa6..551f8fac 100644 --- a/public/categories/software-development/index.html +++ b/public/categories/software-development/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: Software Development · GeekyRyan + - - -Software Development - GeekyRyan - - - - - - - - - - + - - - - - + + + + + + + + + + + + - - - - - - - - + + + + - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,858 +79,232 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - - -
    -
    - -

    Category: Software Development

    - - - -
    -
    -
    -

    Using try/catch/finally Blocks in PowerShell

    -
    - -
    - - -
    - Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it’s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we’ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn’t crash when the unexpected occurs. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Golang: When Identical Strings are Not Equal

    -
    - -
    - - -
    - This will be a quick and dirty post, so please forgive any spelling/grammar mistakes. -I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don’t write a ton of code at work (mostly just scripting/pipelines when I do), so I’m constantly working on something like this in my spare time. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Handling Graceful Shutdown in a .NET App Hosted in Kubernetes

    -
    - -
    - - -
    - I was recently involved with troubleshooting some API’s hosted in Kubernetes throwing http/502’s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. -
    - - -
    - Read more -
    - - - - - - - -
    - -
    -
    -
    -

    Building a Golang App with Github Actions

    -
    - -
    - - -
    - In this article, we’ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app written in any language though. We’ll cover the following: -What are github actions? Setting up the workflow to build, test, and deploy a binary Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. -
    - - -
    - Read more -
    - - - - - - -
    +
  • + 2024-03-27 + Detecting MIME Types in Go +
  • -
    -
    -
    -

    Chaining YAML Pipelines in Azure Devops

    -
    - -
    - +
  • + 2023-12-19 + Validating URLs with Go +
  • -
    - In this article, we’ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to figure this out. -Our two pipelines will exist in the same repository. -
    +
  • + 2023-08-15 + Using try/catch/finally Blocks in PowerShell +
  • +
  • + 2023-01-24 + Golang: When Identical Strings are Not Equal +
  • -
    - Read more -
    +
  • + 2022-12-28 + Handling Graceful Shutdown in a .NET App Hosted in Kubernetes +
  • +
  • + 2022-12-23 + Building a Golang App with Github Actions +
  • +
  • + 2022-11-03 + Chaining YAML Pipelines in Azure Devops +
  • - +
  • + 2022-09-12 + Update Azure Devops SPN Secret +
  • - - - -
    - -
    -
    -
    -

    Update Azure Devops SPN Secret

    -
    - -
    - -
    - If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal. -In this article, I’ll show you two methods for updating a secret for a service principal prior to expiration. -Update the secret via the Azure Devops Portal: Go to “Service Connections” in the Azure Devops portal Find the SPN you want to update, then click “Manage Service Principal” Then on the service principal page, click Certificates & Secrets Create a “New Client Secret”, take note of the value Delete the ‘old’ secret Return to the Service Connection in the Azure Devops portal Click Edit - click the verify button. -
    - - -
    - Read more -
    - - - - - - - -
    + -
    -
    -
    -

    Use “replace” in go.mod to Point to a Local Module

    -
    - -
    - -
    - If you want to the local version of a dependency in Go rather than one in a remote repository, use the replace keyword. -The replace line goes above your require statements, like so: -module github.com/rnemeth90/foo replace github.com/rnemeth90/bar => /Users/rnemeth90/Projects/bar require ( github.com/rnemeth90/bar v1.0.0 ) Now when you compile this module go build or go install, it will use your local code rather than the remote dependency. -According to the docs, you do need to make sure that the code you’re pointing to also has a go. -
    + +
  • 1
  • + + -
    - Read more -
    + - + +
  • 2
  • + - - - -
    - -
    -
    -
    -

    Powershell for Devops - Querying REST APIs with Powershell

    -
    -
    +
    +
    + © -
    - This will be a short post on querying REST APIs with Powershell. -It’s hard to argue that REST APIs are the predominant technology for interacting with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) product without having to go through the exercise of a more complicated integration. REST APIs communicate in a common format, typically JSON. However, most will allow us to choose the response format by specifying an option in the ‘Accept’ header. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - - -
    +
    +
    -
    - - - - - - -
    -
    + - - -
    -
    -
    -

    Reading Json Files with Go

    -
    - -
    + + + + - -
    - JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting with it, and most public APIs accept JSON in HTTP requests. -In this post, we’ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the JSON data within the file into a memory structure. -
    - - -
    - Read more -
    - - - + - + -
    - - - + + - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ - Ryan -
    - - - - - - -
    -
    + -
    - - + + + - - - + - - + + diff --git a/public/categories/software-development/index.xml b/public/categories/software-development/index.xml index 8f43c8e8..4a9d4ee0 100644 --- a/public/categories/software-development/index.xml +++ b/public/categories/software-development/index.xml @@ -2,782 +2,88 @@ Software Development on GeekyRyan - https://rnemeth90.github.io/categories/software-development/ - GeekyRyan (Software Development) - Hugo -- gohugo.io - en-us - Tue, 15 Aug 2023 00:00:00 +0000 - - - - + http://localhost:1313/categories/software-development/ + Recent content in Software Development on GeekyRyan + Hugo + en + Wed, 27 Mar 2024 00:00:00 +0000 + + + Detecting MIME Types in Go + http://localhost:1313/posts/2024-03-27-golang-detect-file-type/ + Wed, 27 Mar 2024 00:00:00 +0000 + http://localhost:1313/posts/2024-03-27-golang-detect-file-type/ + Introduction Link to heading Knowing the type of a file you&rsquo;re working with is not just a matter of curiosity — it&rsquo;s often a necessity. This is especially true when you&rsquo;re deciding whether or not a particular operation can be carried out on that file. Go, with its comprehensive standard library, offers a straightforward approach to identifying a file&rsquo;s MIME type, ensuring that developers have the tools they need to make informed decisions about file manipulation. + + + Validating URLs with Go + http://localhost:1313/posts/2023-12-12-golang-url-validation/ + Tue, 19 Dec 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-12-12-golang-url-validation/ + Introduction Link to heading In this post, we&rsquo;ll take a quick look at URL validation using Golang. It&rsquo;s common to implement URL validation as a task within a HTTP request pipeline, typically as middleware. There are many different definitions of &ldquo;validation&rdquo;. For the purpose of this article, we will simply validate that a URL conforms to a particular text pattern. I often see people (mistakenly) use URL and URI interchangeably. + Using try/catch/finally Blocks in PowerShell - https://rnemeth90.github.io/posts/2023-08-15-powershell-try-catch/ + http://localhost:1313/posts/2023-08-15-powershell-try-catch/ Tue, 15 Aug 2023 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2023-08-15-powershell-try-catch/ - <p>Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it&rsquo;s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we&rsquo;ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn&rsquo;t crash when the unexpected occurs. We&rsquo;ll then cover the differences in terminating and non-terminating errors and why you should take these into consideration when implementing error handling.</p> -<h2 id="the-try-block" >The Try Block -<span> - <a href="#the-try-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The Try block is where you place the code that might generate an error. Think of it as a protective bubble around your potentially troublesome code. If an error occurs within the Try block, PowerShell will immediately jump to the corresponding Catch block.</p> -<p>Here&rsquo;s a simple example:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><h2 id="the-catch-block" >The Catch Block -<span> - <a href="#the-catch-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The Catch block is where you can handle the error. PowerShell provides you with a special variable $_ that contains information about the error. You can use this variable to display error messages or even take corrective actions.</p> -<p>In the example above, we&rsquo;re capturing the error generated by attempting to retrieve a nonexistent file. The $_ variable holds the error message, which we&rsquo;re displaying using Write-Host.</p> -<h2 id="the-finally-block" >The Finally Block -<span> - <a href="#the-finally-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Now, let&rsquo;s talk about the unsung hero – the Finally block. This block is executed regardless of whether an error occurred or not. It&rsquo;s where you can place cleanup code that ensures your script leaves no trace behind, even in the face of adversity. Some tasks that are commonly done in the finally block are closing database connections, removing temp files, etc. The finally block is completely optional.</p> -<pre tabindex="0"><code> -try { - # Code that might generate an error - # ... -} -catch { - # Code to handle the error - # ... -} -finally { - # Cleanup code here - # ... -} -</code></pre><h2 id="terminatingnon-terminating-errors" >Terminating/non-terminating Errors -<span> - <a href="#terminatingnon-terminating-errors"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>non-terminating errors are any error that will not stop the execution of your script. Most cmdlets in PowerShell are non-terminating. They may output an error, but your script will continue to run. These kinds of errors cannot be caught with a catch block by default. The reason for this is the default <code>ErrorAction</code> in your PowerShell profile, which is set to <code>Continue</code>.</p> -<pre tabindex="0"><code># To show your default error action type -$ErrorActionPreference -</code></pre><p>Let&rsquo;s go back and look at our first example:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><p>If you took the time to run this code, you may have noticed that the <code>Write-Host</code> cmdlet in the <code>catch</code> block was never ran. Why did we get a red error message in our PowerShell console, rather than the text <code>An error occurred: ...</code>? The reason is that the non-existing path isn&rsquo;t a terminating error, and the default <code>ErrorAction</code> is <code>Continue</code>. To catch the error, you will need to change the <code>ErrorAction</code> in your PowerShell console to <code>Stop</code>. This can be done in multiple ways. You can add <code>-ErrorAction Stop</code> to the cmdlet, like this:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -ErrorAction Stop -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><p>Or you can change the <code>ErrorActionPreference</code> for the entire script, by adding this to the top of the script:</p> -<pre tabindex="0"><code>$ErrorActionPreference = &#34;Stop&#34; -</code></pre><h2 id="exceptions" >Exceptions -<span> - <a href="#exceptions"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>If you have ever worked with exceptions in C# you can skip this section. In the previous examples, we used simple <code>catch</code> blocks that will catch <em>any</em> error. This is a good start, but we can do better. PowerShell allows you to catch individual exceptions based on the exception type, similar to how C# handles catching exceptions.</p> -<p>Let&rsquo;s look at an example:</p> -<pre tabindex="0"><code>try { - # Attempt to open a non-existent file - $file = Get-Content -Path &#34;NonexistentFile.txt&#34; -} -catch [System.IO.FileNotFoundException] { - Write-Host &#34;Caught a FileNotFoundException: $_&#34; -} -catch { - Write-Host &#34;Caught an exception: $_&#34; -} -</code></pre><p>We now have two <code>catch</code> blocks. If we encounter an exception of type <code>System.IO.FileNotFoundException</code>, the first <code>catch</code> block will catch the exception and handle it accordingly. The second <code>catch</code> block will handle any other generic error.</p> -<h2 id="conclusion" >Conclusion -<span> - <a href="#conclusion"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Error handling might seem daunting at first, but with the power of Try-Catch-Finally blocks at your fingertips, you&rsquo;re well-equipped to handle errors gracefully and ensure the resilience of your PowerShell scripts. Remember, every error is an opportunity to refine your skills and make your scripts more robust.</p> -<p>Thanks for reading!</p> -<p>Official Microsoft Documentation for Try-Catch-Finally in PowerShell: -<a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-7.3">about_try_catch_finally</a></p> - + http://localhost:1313/posts/2023-08-15-powershell-try-catch/ + Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it&rsquo;s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we&rsquo;ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn&rsquo;t crash when the unexpected occurs. - Golang: When Identical Strings are Not Equal - https://rnemeth90.github.io/posts/2023-01-24-golang-strings-not-equal/ + http://localhost:1313/posts/2023-01-24-golang-strings-not-equal/ Tue, 24 Jan 2023 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2023-01-24-golang-strings-not-equal/ - <p><em>This will be a quick and dirty post, so please forgive any spelling/grammar mistakes.</em></p> -<p>I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don&rsquo;t write a ton of code at work (mostly just scripting/pipelines when I do), so I&rsquo;m constantly working on something like this in my spare time. Anyway, I was writing this app, got everything working like I wanted it to. I then wrote some of the tests and was iterating over them. I noticed the <code>ListTasks</code> test was failing:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TestAddTask</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">task</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;test task number 1&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Getwd</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmdPath</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">binaryName</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;AddNewTask&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-add&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">Run</span>(); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// failing test -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;ListTasks&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-list&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">out</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">CombinedOutput</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">expected</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;[ ] 1: %s&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Compare</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#a6e22e">expected</span>) <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;got %v, expected %v\n&#34;</span>, <span style="color:#a6e22e">out</span>, []byte(<span style="color:#a6e22e">expected</span>)) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Seems strange, considering the strings appear to be equivalent in the output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span> main_test.go:82: got <span style="color:#f92672">[</span> <span style="color:#f92672">]</span> 1: test task number <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> , expected <span style="color:#f92672">[</span> <span style="color:#f92672">]</span> 1: test task number <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>--- FAIL: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- FAIL: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>FAIL -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>exit status <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>FAIL github.com/rnemeth90/todo/cmd/todo 0.105s -</span></span></code></pre></div><p>What could be happening? After banging my head on the desk a few times, a revelation came to me&hellip;</p> -<p>In Go, strings are simply slices of bytes. I decided to print out each string as a byte array:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span> main_test.go:80: got <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">10</span> 10<span style="color:#f92672">]</span>, expected <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> 49<span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span>--- FAIL: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- FAIL: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>FAIL -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>exit status <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>FAIL github.com/rnemeth90/todo/cmd/todo 0.144s -</span></span></code></pre></div><p>Let&rsquo;s take a closer look at the byte arrays from the test output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>got <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">10</span> 10<span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span>expected <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> 49<span style="color:#f92672">]</span> -</span></span></code></pre></div><p>We can see the byte array returned from <code>cmd.CombinedOutput()</code> has some additional bytes in it at the end (32,10,10). What exactly are 32, 10, and 10? To figure this out, I went over to the go playground: <a href="https://go.dev/play/">https://go.dev/play/</a>.</p> -<p>Let&rsquo;s see what happens when we create a byte array with a single number and print it out as a string to the console:</p> -<p><a href="https://rnemeth90.github.io/images/golang-strings-not-equal-01.png"><img src="https://rnemeth90.github.io/images/golang-strings-not-equal-01.png" alt=""></a></p> -<p>Interesting, we can see that <code>m</code> was output to the console. So what do our mysterious additional characters in our test result represent? Let&rsquo;s see:</p> -<p><a href="https://rnemeth90.github.io/images/golang-strings-not-equal-02.png"><img src="https://rnemeth90.github.io/images/golang-strings-not-equal-02.png" alt=""></a></p> -<p>It&rsquo;s hard to tell from the output, but if you look in the results pane, you&rsquo;ll see a space and two new lines. So <code>32</code> represents a space, and <code>10</code> represents a new line!</p> -<p>You can play with this code yourself: <a href="https://go.dev/play/p/fGUIxJM6KnV">https://go.dev/play/p/fGUIxJM6KnV</a></p> -<p>Ok, so let&rsquo;s fix our failing test:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TestAddTask</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">task</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;test task number 1&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Getwd</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmdPath</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">binaryName</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;AddNewTask&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-add&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">Run</span>(); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;ListTasks&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-list&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">out</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">CombinedOutput</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// add this line -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">out</span> = []byte(<span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">TrimSuffix</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#e6db74">&#34; \n\n&#34;</span>)) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">expected</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;[ ] 1: %s&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Compare</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#a6e22e">expected</span>) <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;got %v, expected %v\n&#34;</span>, <span style="color:#a6e22e">out</span>, []byte(<span style="color:#a6e22e">expected</span>)) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>The <code>strings</code> package has a <code>TrimSuffix</code> function that is useful for trimming bits off the end of a string. In the code above, you can see that we added <code>out = []byte(strings.TrimSuffix(string(out), &quot; \n\n&quot;))</code>, which will trim off the space (character 32) and the two new lines (character 10). Now when we run our integration test, it passes:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span>--- PASS: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>PASS -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>ok github.com/rnemeth90/todo/cmd/todo 0.106s -</span></span></code></pre></div> + http://localhost:1313/posts/2023-01-24-golang-strings-not-equal/ + This will be a quick and dirty post, so please forgive any spelling/grammar mistakes. I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don&rsquo;t write a ton of code at work (mostly just scripting/pipelines when I do), so I&rsquo;m constantly working on something like this in my spare time. - Handling Graceful Shutdown in a .NET App Hosted in Kubernetes - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ Wed, 28 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ - <p>I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. It was actually a combination of these blogs (and the resolutions posted) that ended up resolving our issue.</p> -<h3 id="so-what-was-actually-causing-the-502s" >So what was actually causing the 502&rsquo;s? -<span> - <a href="#so-what-was-actually-causing-the-502s"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h3><p>As stated, these APIs are hosted in Kubernetes. They are written primarily in c# (.NET Framework) and hosted in Windows Server Core containers. The pods are load balanced using a service, and we have an Nginx ingress on top of the service. Nothing fancy, just a typical setup that you may have seen or even built yourself. We implement automatic scaling for our replica sets using a standard Kubernetes-native HPA or Keda, depending on the app. We have autoscale rules defined for the pods. Our clusters are hosted in Azure Kubernetes Service, and we autoscale our node pools. So, there are several layers of scaling happening in our clusters at any given time. Occasionally, when a pod was handling a client request, Kubelet or a controller would come along and scale the pod in. We were initially under the belief that the <code>terminationGracePeriodSeconds</code> value within our deployment would allow the pod to continue running for the defined number of seconds. However, we were mistaken. This value tells Kubernetes to allow the application running within the pod some time to clean up. It does <em>not</em> tell the app to continue running for the defined number of seconds after it receives a sigterm signal. This logic actually needs to be implemented within the application itself, or with a prestop hook. The prestop method is <a href="https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/">well documented</a>, so I will not cover it here.</p> -<p>To implement this in a .NET Framework app running in Windows, you need to add this registry key to your container.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">RUN</span> reg add hklm<span style="color:#ae81ff">\s</span>ystem<span style="color:#ae81ff">\c</span>urrentcontrolset<span style="color:#ae81ff">\c</span>ontrol /v WaitToKillServiceTimeout /t REG_SZ /d <span style="color:#ae81ff">60000</span> /f<span style="color:#960050;background-color:#1e0010"> -</span></span></span></code></pre></div><p>This value tells Windows to wait a number of milliseconds before shutting down Normally, Windows only waits for 5 seconds (default) before shutting down any &lsquo;background&rsquo; processes. Windows forcibly shuts down processes after this period of time.</p> -<p>Next, in the startup class, we&rsquo;ll add the following code. I have added inline comments to explain.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c#" data-lang="c#"><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">namespace</span> MyApp.APIConsoleHost -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Program</span> -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Register the SetConsoleCtrlHandler function in kernel32.dll in the -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> application to capture CTRL_SHUTDOWN_EVENT events for resource reclamation -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e"> [DllImport(&#34;Kernel32&#34;)]</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">extern</span> <span style="color:#66d9ef">bool</span> SetConsoleCtrlHandler(HandlerRoutine handler, <span style="color:#66d9ef">bool</span> <span style="color:#66d9ef">add</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Define a delegate for our handler routine</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">delegate</span> <span style="color:#66d9ef">bool</span> HandlerRoutine(CtrlTypes ctrlType); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">volatile</span> ManualResetEvent _exitEvent = <span style="color:#66d9ef">new</span> ManualResetEvent(<span style="color:#66d9ef">false</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> HandlerRoutine _handler; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Define the event types that we want to handle when the application receives a SIGTERM -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_C_EVENT = 0, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_BREAK_EVENT = 1, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_CLOSE_EVENT = 2, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_LOGOFF_EVENT = 5, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_SHUTDOWN_EVENT = 6 -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">enum</span> CtrlTypes -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> CTRL_SHUTDOWN_EVENT = <span style="color:#ae81ff">6</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Here we are defining how we want to handle the shutdown -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We get a timeout value from an env variable named APP_SHUTDOWN_TIMEOUT -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> If that env variable is not found, we default to 60 seconds. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We then switch on our CtrlTypes enum and handle each value accordingly, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then return true. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">bool</span> ConsoleCtrlCheck(CtrlTypes ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> timeout = ConfigurationManager.AppSettings[<span style="color:#e6db74">&#34;APP_SHUTDOWN_TIMEOUT&#34;</span>]; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> (<span style="color:#66d9ef">string</span>.IsNullOrEmpty(timeout)) { timeout = <span style="color:#e6db74">&#34;60&#34;</span>; } -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">int</span> counter = <span style="color:#66d9ef">int</span>.Parse(timeout); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">switch</span> (ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> CtrlTypes.CTRL_SHUTDOWN_EVENT: -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] CTRL_SHUTDOWN received&#34;</span>); -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] Web Server is stopping in {counter} seconds&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">while</span> (counter &gt; <span style="color:#ae81ff">0</span>) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> Thread.Sleep(TimeSpan.FromSeconds(<span style="color:#ae81ff">1</span>)); -</span></span><span style="display:flex;"><span> counter--; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.Set(); -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span>; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span>: -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">false</span>; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Our main method is pretty standard. However, we first register a new handler (_handler), -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then pass it to to the SetConsoleCtrlHandler() method we imported from Kernel32.dll. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> The only other &#39;unique&#39; thing is the _exitEvent.WaitOne(); call defined at the bottom of main(). -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> This is necessary so that main does not immediately exit, and wait&#39;s for a signal. We defined a -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> property for this _exitEvent of type ManualResetEvent at the top of this class file. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> Main(<span style="color:#66d9ef">string</span>[] args) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> _handler += <span style="color:#66d9ef">new</span> HandlerRoutine(ConsoleCtrlCheck); -</span></span><span style="display:flex;"><span> SetConsoleCtrlHandler(_handler, <span style="color:#66d9ef">true</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = BuildStartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> WebApp.Start&lt;SelfHostStartup&gt;(startOptions); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">&#34;Press CTRL+C to stop it&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.WaitOne(); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> StartOptions BuildStartOptions() -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = <span style="color:#66d9ef">new</span> StartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted start options</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> startOptions; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>To prevent the HandlerRoutine instance from being recycled by the GC before the program exits, the HandlerRoutine must be static (as seen in the above example). This is important because if the handlerroutine is recycled before the application is finished, it will throw an error, as shown here:</p> -<pre tabindex="0"><code>A callback was made on a garbage collected delegate of type &#39;Program+HandlerRoutine::Invoke&#39;. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called. -</code></pre> + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. - Building a Golang App with Github Actions - https://rnemeth90.github.io/posts/2022-12-24-gh-actions-copy/ + http://localhost:1313/posts/2022-12-24-gh-actions-copy/ Fri, 23 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-24-gh-actions-copy/ - <p>In this article, we&rsquo;ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app -written in any language though. We&rsquo;ll cover the following:</p> -<ol> -<li>What are github actions?</li> -<li>Setting up the workflow to build, test, and deploy a binary</li> -</ol> -<p>Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. They are powerful and I suggest you read more at the <a href="https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions">Official Docs</a></p> -<p>To get started, we&rsquo;ll need a golang app to build. You can use my example <a href="https://github.com/rnemeth90/golang-github-action-example">here</a> if you do not have your own.</p> -<p>The process is relatively simple. At the root of your repo, create the following directories:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>mkdir -p .github/workflows -</span></span></code></pre></div><p>Then create a yaml file (you can name it anything you want) with the content below:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">name</span>: <span style="color:#ae81ff">build-release-binary</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">run-name</span>: <span style="color:#ae81ff">Create Github Release for GoLang binary</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># anytime we push to our repo with a tag starting with the</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># letter &#39;r&#39;, we run the build</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">on</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">push</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tags</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#e6db74">&#39;r*&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">jobs</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">build</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">runs-on</span>: <span style="color:#ae81ff">ubuntu-22.04</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">permissions</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">contents</span>: <span style="color:#ae81ff">write</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># checkout our github repo to the build agent</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/checkout@v3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">fetch-depth</span>: <span style="color:#ae81ff">0</span> <span style="color:#75715e"># get all tags, needed to get git log</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">ref</span>: <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Setup the Go environment</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">setup Go Lang</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">id</span>: <span style="color:#ae81ff">build</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/setup-go@v3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">go-version</span>: <span style="color:#e6db74">&#39;^1.19.2&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Build our application</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go version -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> cd src -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [ ! -e *.mod ]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go mod init ${GITHUB_REPOSITORY} -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go mod tidy -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go build -ldflags &#34;-X main.Version=${GITHUB_REF_NAME} -X main.BuiltBy=github-actions&#34; main.go -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> execFile=$(find . -type f -executable)</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Output more values for debugging</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git version</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git branch</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git tag</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># tag our release</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">get semantic tag version and release notes from commit messages</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">id</span>: <span style="color:#ae81ff">tag</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">run</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> currentTag=${GITHUB_REF_NAME} -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> major_minor=$(echo &#34;$currentTag&#34; | cut -d&#39;.&#39; -f1-2) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> patch=$(echo &#34;$currentTag&#34; | cut -d&#39;.&#39; -f3) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> # avoid empty patch number -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> [ -n &#34;$patch&#34; ] &amp;&amp; ((patch--)) || patch=&#34;.x&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> previousTag=&#34;${major_minor}.${patch}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;&#34; &gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if git tag | grep $previousTag ; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git log -q ${currentTag}...${previousTag} --pretty=&#34;- %s&#34; -q --no-color &gt;&gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> else -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git log --pretty=&#34;- %s&#34; -q --no-color &gt;&gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> line_count=$(cat body.log | wc -l) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;currentTag=$currentTag&#34; &gt;&gt; $GITHUB_OUTPUT -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;previousTag=$previousTag&#34; &gt;&gt; $GITHUB_OUTPUT -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;line_count=$line_count&#34; &gt;&gt; $GITHUB_OUTPUT</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># create Github release with release note from file and binary asset attached</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">ncipollo/release-action@v1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">${{ env.GITHUB_REF_NAME }}</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tag</span>: <span style="color:#ae81ff">${{ env.GITHUB_REF_NAME }}</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">artifacts</span>: <span style="color:#e6db74">&#34;src/main&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">bodyFile</span>: <span style="color:#e6db74">&#34;body.log&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">token</span>: <span style="color:#ae81ff">${{ secrets.GITHUB_TOKEN }}</span> -</span></span></code></pre></div><p>Each step within this workflow starts with a hyphen. The steps are well-commented, so I will not explain them further. Once you have this file in your repo, push it to github. Then navigate to the Actions tab in your repository and you should see your workflow on the left hand side of the screen.</p> -<p><a href="https://rnemeth90.github.io/images/gh-actions-1.png"><img src="https://rnemeth90.github.io/images/gh-actions-1.png" alt=""></a></p> -<p>Now that we have our workflow setup, to get it run, all you need to do is tag and push your release to github. To do that, you can run the script in my repo <a href="https://github.com/rnemeth90/golang-github-action-example/blob/main/create_new_gh_release.sh">create_new_gh_release.sh</a> or simply run the following commands (be sure to change the tag as needed):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>newtag<span style="color:#f92672">=</span>r1.0.0 -</span></span><span style="display:flex;"><span>git tag $newtag <span style="color:#f92672">&amp;&amp;</span> git push origin $newtag -</span></span></code></pre></div><p>Now, go back to the Actions tab in your repo, and you should see the build running. Once it completes, go back to the Code tab in your github repo and you will see the release on the right hand side of the screen.</p> -<p><a href="https://rnemeth90.github.io/images/gh-actions-2.png"><img src="https://rnemeth90.github.io/images/gh-actions-2.png" alt=""></a></p> - + http://localhost:1313/posts/2022-12-24-gh-actions-copy/ + In this article, we&rsquo;ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app written in any language though. We&rsquo;ll cover the following: What are github actions? Setting up the workflow to build, test, and deploy a binary Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. - Chaining YAML Pipelines in Azure Devops - https://rnemeth90.github.io/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ + http://localhost:1313/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ Thu, 03 Nov 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ - <p>In this article, we&rsquo;ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. -Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to -figure this out.</p> -<p>Our two pipelines will exist in the same repository. We have a dependent-pipeline, that we only want to run once the source-pipeline is finished. This is useful if you have -some infrastructure you want to build, prior to deploying something to that infrastructure.</p> -<p>The process is actually quite simple. First, let&rsquo;s define our source pipeline:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># source-pipeline</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: <span style="color:#ae81ff">echo Hello, world!</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a one-line script&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo Add other tasks to build, test, and deploy your project. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo See https://aka.ms/yaml</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a multi-line script&#39;</span> -</span></span></code></pre></div><p>Nothing fancy here, just the build in template pipeline that Microsoft gives us for free when we create a &ldquo;Starter Pipeline&rdquo;.</p> -<p>Now, let&rsquo;s create another pipeline in the same repo that will be triggered when the pipeline above completes:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># dependent-pipeline</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">none</span> <span style="color:#75715e"># we want this pipeline to be triggered manually, not based on PR, etc.</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">pipelines</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">pipeline</span>: <span style="color:#ae81ff">source-pipeline</span> <span style="color:#75715e">#this can be anything</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">source</span>: <span style="color:#e6db74">&#39;source-pipeline&#39;</span> <span style="color:#75715e">#this needs to be the name of the &#39;source&#39; pipeline</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">trigger</span>: <span style="color:#66d9ef">true</span> <span style="color:#75715e"># Run dependent-pipeline pipeline when any run of security-lib-ci completes</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: <span style="color:#ae81ff">echo Hello, world!</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a one-line script&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo Add other tasks to build, test, and deploy your project. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo See https://aka.ms/yaml</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a multi-line script&#39;</span> -</span></span></code></pre></div><p>The resources block above defines our dependency. You want to be sure to configure the trigger of the dependent pipeline appropriately as well.</p> -<p>There are several options for fine-tuning this process. See the office Microsoft documentation below:</p> -<p><a href="https://learn.microsoft.com/en-us/azure/devops/pipelines/process/pipeline-triggers?view=azure-devops">Link to the Microsoft Docs</a></p> - + http://localhost:1313/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ + In this article, we&rsquo;ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to figure this out. Our two pipelines will exist in the same repository. - Update Azure Devops SPN Secret - https://rnemeth90.github.io/posts/2022-09-12-update-azure-devops-spn-secret/ + http://localhost:1313/posts/2022-09-12-update-azure-devops-spn-secret/ Mon, 12 Sep 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-09-12-update-azure-devops-spn-secret/ - <p>If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal.</p> -<p>In this article, I&rsquo;ll show you two methods for updating a secret for a service principal prior to expiration.</p> -<h1 id="update-the-secret-via-the-azure-devops-portal" >Update the secret via the Azure Devops Portal: -<span> - <a href="#update-the-secret-via-the-azure-devops-portal"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h1><ul> -<li>Go to &ldquo;Service Connections&rdquo; in the Azure Devops portal</li> -<li>Find the SPN you want to update, then click &ldquo;Manage Service Principal&rdquo;</li> -<li>Then on the service principal page, click Certificates &amp; Secrets</li> -<li>Create a &ldquo;New Client Secret&rdquo;, take note of the value</li> -<li>Delete the &lsquo;old&rsquo; secret</li> -<li>Return to the Service Connection in the Azure Devops portal</li> -<li>Click Edit - click the verify button. It should tell you the client certificate has expired</li> -<li>Now you need to make an arbitrary change and save it. I just type a character in the optional description and save.</li> -<li>Now edit again and click verify, it will now pick up the new client secret and all is happy.</li> -<li>You can now remove whatever you added to the description.</li> -</ul> - + http://localhost:1313/posts/2022-09-12-update-azure-devops-spn-secret/ + If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal. In this article, I&rsquo;ll show you two methods for updating a secret for a service principal prior to expiration. Update the secret via the Azure Devops Portal: Link to heading Go to &ldquo;Service Connections&rdquo; in the Azure Devops portal Find the SPN you want to update, then click &ldquo;Manage Service Principal&rdquo; Then on the service principal page, click Certificates &amp; Secrets Create a &ldquo;New Client Secret&rdquo;, take note of the value Delete the &lsquo;old&rsquo; secret Return to the Service Connection in the Azure Devops portal Click Edit - click the verify button. - Use “replace” in go.mod to Point to a Local Module - https://rnemeth90.github.io/posts/2022-09-06-go-mod-replace-copy/ + http://localhost:1313/posts/2022-09-06-go-mod-replace-copy/ Tue, 06 Sep 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-09-06-go-mod-replace-copy/ - <p>If you want to the local version of a dependency in Go rather than one in a remote repository, use the <em>replace</em> keyword.</p> -<p>The replace line goes above your require statements, like so:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> module github.com/rnemeth90/foo -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> replace github.com/rnemeth90/bar <span style="color:#f92672">=</span>&gt; /Users/rnemeth90/Projects/bar -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> require <span style="color:#f92672">(</span> -</span></span><span style="display:flex;"><span> github.com/rnemeth90/bar v1.0.0 -</span></span><span style="display:flex;"><span> <span style="color:#f92672">)</span> -</span></span></code></pre></div><p>Now when you compile this module <em>go build</em> or <em>go install</em>, it will use your local code rather than the remote dependency.</p> -<p>According to the docs, you do need to make sure that the code you’re pointing to also has a <strong>go.mod</strong> file:</p> -<blockquote> -<p><strong>Note</strong>: if the right-hand side of a <code>replace</code> directive is a filesystem path, then the target must have a <code>go.mod</code> file at that location. If the <code>go.mod</code> file is not present, you can create one with <code>go mod init</code>.</p> -<p><a href="https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive">https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive</a></p> -</blockquote> -<p>You can also create this line from the command line using the <strong>go mod edit</strong> command.</p> -<pre><code>$ go mod edit -replace github.com/rnemeth90/bar=/Users/rnemeth90/Projects/bar -</code></pre> -<p>Following the <strong>-replace</strong> is first what you want to replace, then an equals sign, then what you’re replacing it with.</p> -<p>Hopefully this helps someone who was stuck with this like me 🙂</p> - + http://localhost:1313/posts/2022-09-06-go-mod-replace-copy/ + If you want to the local version of a dependency in Go rather than one in a remote repository, use the replace keyword. The replace line goes above your require statements, like so: module github.com/rnemeth90/foo replace github.com/rnemeth90/bar =&gt; /Users/rnemeth90/Projects/bar require ( github.com/rnemeth90/bar v1.0.0 ) Now when you compile this module go build or go install, it will use your local code rather than the remote dependency. According to the docs, you do need to make sure that the code you’re pointing to also has a go. - Powershell for Devops - Querying REST APIs with Powershell - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ Thu, 04 Aug 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ - <p>This will be a short post on querying REST APIs with Powershell.</p> -<p>It&rsquo;s hard to argue that REST APIs are the predominant technology for interacting -with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) -product without having to go through the exercise of a more complicated integration. REST APIs communicate -in a common format, typically JSON. However, most will allow us to choose the response format by specifying an -option in the &lsquo;Accept&rsquo; header. Most languages provide a native method for interacting with -REST APIs. This objective for this post is to show you how simple this is with Powershell.</p> -<p>To get started, we&rsquo;ll need a public API to interact with. I&rsquo;m going to use <a href="https://icanhazdadjoke.com/">https://icanhazdadjoke.com/</a>, because -there is no authentication and no rate-limiting (two concepts we will cover in another post).</p> -<p>Calling the API is extremely simple:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -</span></span></code></pre></div><p>However, this results in the content being returned as plain text. This isn&rsquo;t ideal.</p> -<p>Let&rsquo;s pass the &lsquo;Accept&rsquo; header to tell the API the format we are expecting to be returned:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers -</span></span></code></pre></div><p>Output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>[<span style="color:#ae81ff">15</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">04</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">34</span>] C:\..\..\rnemeth90.github.io on <span style="color:#960050;background-color:#1e0010"></span>main <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#ae81ff">+1</span> <span style="color:#960050;background-color:#1e0010">❯</span> Invoke-RestMethod -Uri $url -Method Get -Headers $headers -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>id joke status -</span></span><span style="display:flex;"><span>-- ---- ------ -</span></span><span style="display:flex;"><span>3LmyXvsPfqc I don<span style="color:#e6db74">&#39;t trust stairs. They&#39;</span>re always up to something. <span style="color:#ae81ff">200</span> -</span></span></code></pre></div><p>That looks a little better. For those of you familiar with Powershell, the output above probably -looks completely normal. But for those not-so-familiar with Powershell, or those expecting -more of a &lsquo;json-esk&rsquo; output, this may look a bit&hellip; weird.</p> -<p>Powershell is an object oriented language. <strong>Everything is an object</strong> in Powershell, even the response -of this request. What you see in the output is simply the properties of the object.</p> -<p>Luckily Powershell provides us with a cmdlet to convert an object into json (aptly named: ConvertTo-Json). We can use it like this:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers | ConvertTo-Json -</span></span></code></pre></div><p>Here we are piping the output from Invoke-RestMethod to ConvertTo-Json. Pretty neat!</p> -<p>Output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>[<span style="color:#ae81ff">15</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">04</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">35</span>] C:\..\..\rnemeth90.github.io on <span style="color:#960050;background-color:#1e0010"></span>main <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#ae81ff">+1</span> <span style="color:#960050;background-color:#1e0010">❯</span> Invoke-RestMethod -Uri $url -Method Get -Headers $headers | Convertto-json -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;id&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#e6db74">&#34;AAdFBXnGlyd&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;joke&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#e6db74">&#34;If you walk into a forest and cut down a tree, but the tree doesn&#39;t understand why you cut it down, do you think it&#39;s stumped?&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;status&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#ae81ff">200</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Now, that looks more normal.</p> -<p>There is much more we can do with Invoke-RestMethod. The &lsquo;Method&rsquo; parameter of this cmdlet accepts any of the common -HTTP methods (GET, PUT, PATCH, DELETE, POST, HEAD). You can also specify other headers and a body (using the -body parameter).</p> -<p>Both of these parameters accept dictionaries:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Host&#39;</span> = <span style="color:#e6db74">&#39;MyServer&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>$body = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Eat&#39;</span> = <span style="color:#e6db74">&#39;Pizza&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers -Body $body | ConvertTo-Json -</span></span></code></pre></div><p>Unfortunately I won&rsquo;t be able to show the other HTTP methods, as this API only supports GET requests. So that&rsquo;s all for now.</p> - + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ + This will be a short post on querying REST APIs with Powershell. It&rsquo;s hard to argue that REST APIs are the predominant technology for interacting with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) product without having to go through the exercise of a more complicated integration. REST APIs communicate in a common format, typically JSON. However, most will allow us to choose the response format by specifying an option in the &lsquo;Accept&rsquo; header. - Reading Json Files with Go - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ + http://localhost:1313/posts/2022-07-21-reading-json-files-with-go/ Thu, 21 Jul 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ - <p>JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting -with it, and most public APIs accept JSON in HTTP requests.</p> -<p>In this post, we&rsquo;ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the -JSON data within the file into a memory structure.</p> -<p>Let&rsquo;s assume we have the following JSON data representing an employee:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">1</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Steve&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Rogers&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Captain America&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Department&#34;</span>: <span style="color:#e6db74">&#34;Avengers&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>We need a way of representing this data in memory when decoding it from JSON. For this, we will need to create a struct:</p> -<p>We will build up our go module as we progress through the article</p> -<p>Let&rsquo;s start:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#75715e">// main.go -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> ( -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;encoding/json&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;fmt&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;io/ioutil&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;log&#34;</span> -</span></span><span style="display:flex;"><span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">// Hero represents an hero -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// ALL fields must be exportable! Otherwise the JSON parsing will fail. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Hero</span> <span style="color:#66d9ef">struct</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Id</span> <span style="color:#66d9ef">int</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">FirstName</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">LastName</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Alias</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Group</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() { -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Here we set the log prefix. When reading stack traces, this makes it easier to know -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// where a failure occurred. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">SetPrefix</span>(<span style="color:#e6db74">&#34;main(): &#34;</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// We first need to load the JSON file into memory -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">content</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">ioutil</span>.<span style="color:#a6e22e">ReadFile</span>(<span style="color:#e6db74">&#34;./heros.json&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#e6db74">&#34;Error opening the file: &#34;</span>, <span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Now we parse the JSON data into a memory structure. We know our JSON file will have more than one hero object, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// so we&#39;ll use make() to create a []Hero slice. Since go is a pass-by-value language, we will then use the address-of -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// operator (&amp;) to unmarshal our json data into the heros slice -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">heros</span> <span style="color:#f92672">:=</span> make([]<span style="color:#a6e22e">Hero</span>, <span style="color:#ae81ff">5</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">json</span>.<span style="color:#a6e22e">Unmarshal</span>(<span style="color:#a6e22e">content</span>, <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">heros</span>) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#e6db74">&#34;Error occurred during unmarshal: &#34;</span>, <span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// now we can read/interact with the data. We&#39;ll loop over the array -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// and print the values in memory -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; len(<span style="color:#a6e22e">heros</span>); <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">Id</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">FirstName</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">LastName</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">Group</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Create a file named employees.json with similar data:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>[ -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">1</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Steve&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Rogers&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Captain America&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;group&#34;</span>: <span style="color:#e6db74">&#34;Avengers&#34;</span> -</span></span><span style="display:flex;"><span> }, -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">2</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Clark&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Kent&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Superman&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;group&#34;</span>: <span style="color:#e6db74">&#34;Justice League&#34;</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>] -</span></span></code></pre></div><p>Now, we can run our main.go file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>11:40:47 ryan@xerxes json → go run main.go -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>Steve -</span></span><span style="display:flex;"><span>Rogers -</span></span><span style="display:flex;"><span>Avengers -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span>Clark -</span></span><span style="display:flex;"><span>Kent -</span></span><span style="display:flex;"><span>Justice League -</span></span><span style="display:flex;"><span>11:40:49 ryan@xerxes json -</span></span></code></pre></div><p>Pretty simple! That&rsquo;s why I love go. We accomplished all of this with ~50 lines of code. -Doing something similar in asp.net project would easily double that count and involve creating -multiple files! (nothing against asp.net or c#, I think c# is a great language and use it daily)</p> -<p>Now, &lsquo;go&rsquo; try this!</p> - + http://localhost:1313/posts/2022-07-21-reading-json-files-with-go/ + JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting with it, and most public APIs accept JSON in HTTP requests. In this post, we&rsquo;ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the JSON data within the file into a memory structure. - diff --git a/public/categories/software-development/page/1/index.html b/public/categories/software-development/page/1/index.html index 0e40b365..180f7173 100644 --- a/public/categories/software-development/page/1/index.html +++ b/public/categories/software-development/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/software-development/ - + http://localhost:1313/categories/software-development/ + - + diff --git a/public/categories/software-development/page/2/index.html b/public/categories/software-development/page/2/index.html new file mode 100644 index 00000000..3563af21 --- /dev/null +++ b/public/categories/software-development/page/2/index.html @@ -0,0 +1,265 @@ + + + + + Category: Software Development · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + +
    + + + +
    + +
    +
    +

    + Category: Software Development +

    +
    + + + + + + + + +
      + + +
    • «
    • + + + + + + + + + + +
    • 1
    • + + + + + + + + + +
    • 2
    • + + + + +
    + + +
    + + +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/categories/sre/index.html b/public/categories/sre/index.html index 71f21718..30d5baf1 100644 --- a/public/categories/sre/index.html +++ b/public/categories/sre/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: SRE · GeekyRyan + - - -SRE - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,303 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Category: SRE

    - - - -
    -
    -
    -

    Handling Graceful Shutdown in a .NET App Hosted in Kubernetes

    -
    -
    +
    +
    + © -
    - I was recently involved with troubleshooting some API’s hosted in Kubernetes throwing http/502’s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - - + + diff --git a/public/categories/sre/index.xml b/public/categories/sre/index.xml index 7186971c..1266f2ae 100644 --- a/public/categories/sre/index.xml +++ b/public/categories/sre/index.xml @@ -2,137 +2,18 @@ SRE on GeekyRyan - https://rnemeth90.github.io/categories/sre/ - GeekyRyan (SRE) - Hugo -- gohugo.io - en-us + http://localhost:1313/categories/sre/ + Recent content in SRE on GeekyRyan + Hugo + en Wed, 28 Dec 2022 00:00:00 +0000 - - - - + Handling Graceful Shutdown in a .NET App Hosted in Kubernetes - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ Wed, 28 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ - <p>I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. It was actually a combination of these blogs (and the resolutions posted) that ended up resolving our issue.</p> -<h3 id="so-what-was-actually-causing-the-502s" >So what was actually causing the 502&rsquo;s? -<span> - <a href="#so-what-was-actually-causing-the-502s"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h3><p>As stated, these APIs are hosted in Kubernetes. They are written primarily in c# (.NET Framework) and hosted in Windows Server Core containers. The pods are load balanced using a service, and we have an Nginx ingress on top of the service. Nothing fancy, just a typical setup that you may have seen or even built yourself. We implement automatic scaling for our replica sets using a standard Kubernetes-native HPA or Keda, depending on the app. We have autoscale rules defined for the pods. Our clusters are hosted in Azure Kubernetes Service, and we autoscale our node pools. So, there are several layers of scaling happening in our clusters at any given time. Occasionally, when a pod was handling a client request, Kubelet or a controller would come along and scale the pod in. We were initially under the belief that the <code>terminationGracePeriodSeconds</code> value within our deployment would allow the pod to continue running for the defined number of seconds. However, we were mistaken. This value tells Kubernetes to allow the application running within the pod some time to clean up. It does <em>not</em> tell the app to continue running for the defined number of seconds after it receives a sigterm signal. This logic actually needs to be implemented within the application itself, or with a prestop hook. The prestop method is <a href="https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/">well documented</a>, so I will not cover it here.</p> -<p>To implement this in a .NET Framework app running in Windows, you need to add this registry key to your container.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">RUN</span> reg add hklm<span style="color:#ae81ff">\s</span>ystem<span style="color:#ae81ff">\c</span>urrentcontrolset<span style="color:#ae81ff">\c</span>ontrol /v WaitToKillServiceTimeout /t REG_SZ /d <span style="color:#ae81ff">60000</span> /f<span style="color:#960050;background-color:#1e0010"> -</span></span></span></code></pre></div><p>This value tells Windows to wait a number of milliseconds before shutting down Normally, Windows only waits for 5 seconds (default) before shutting down any &lsquo;background&rsquo; processes. Windows forcibly shuts down processes after this period of time.</p> -<p>Next, in the startup class, we&rsquo;ll add the following code. I have added inline comments to explain.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c#" data-lang="c#"><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">namespace</span> MyApp.APIConsoleHost -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Program</span> -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Register the SetConsoleCtrlHandler function in kernel32.dll in the -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> application to capture CTRL_SHUTDOWN_EVENT events for resource reclamation -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e"> [DllImport(&#34;Kernel32&#34;)]</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">extern</span> <span style="color:#66d9ef">bool</span> SetConsoleCtrlHandler(HandlerRoutine handler, <span style="color:#66d9ef">bool</span> <span style="color:#66d9ef">add</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Define a delegate for our handler routine</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">delegate</span> <span style="color:#66d9ef">bool</span> HandlerRoutine(CtrlTypes ctrlType); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">volatile</span> ManualResetEvent _exitEvent = <span style="color:#66d9ef">new</span> ManualResetEvent(<span style="color:#66d9ef">false</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> HandlerRoutine _handler; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Define the event types that we want to handle when the application receives a SIGTERM -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_C_EVENT = 0, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_BREAK_EVENT = 1, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_CLOSE_EVENT = 2, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_LOGOFF_EVENT = 5, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_SHUTDOWN_EVENT = 6 -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">enum</span> CtrlTypes -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> CTRL_SHUTDOWN_EVENT = <span style="color:#ae81ff">6</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Here we are defining how we want to handle the shutdown -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We get a timeout value from an env variable named APP_SHUTDOWN_TIMEOUT -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> If that env variable is not found, we default to 60 seconds. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We then switch on our CtrlTypes enum and handle each value accordingly, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then return true. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">bool</span> ConsoleCtrlCheck(CtrlTypes ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> timeout = ConfigurationManager.AppSettings[<span style="color:#e6db74">&#34;APP_SHUTDOWN_TIMEOUT&#34;</span>]; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> (<span style="color:#66d9ef">string</span>.IsNullOrEmpty(timeout)) { timeout = <span style="color:#e6db74">&#34;60&#34;</span>; } -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">int</span> counter = <span style="color:#66d9ef">int</span>.Parse(timeout); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">switch</span> (ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> CtrlTypes.CTRL_SHUTDOWN_EVENT: -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] CTRL_SHUTDOWN received&#34;</span>); -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] Web Server is stopping in {counter} seconds&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">while</span> (counter &gt; <span style="color:#ae81ff">0</span>) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> Thread.Sleep(TimeSpan.FromSeconds(<span style="color:#ae81ff">1</span>)); -</span></span><span style="display:flex;"><span> counter--; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.Set(); -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span>; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span>: -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">false</span>; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Our main method is pretty standard. However, we first register a new handler (_handler), -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then pass it to to the SetConsoleCtrlHandler() method we imported from Kernel32.dll. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> The only other &#39;unique&#39; thing is the _exitEvent.WaitOne(); call defined at the bottom of main(). -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> This is necessary so that main does not immediately exit, and wait&#39;s for a signal. We defined a -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> property for this _exitEvent of type ManualResetEvent at the top of this class file. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> Main(<span style="color:#66d9ef">string</span>[] args) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> _handler += <span style="color:#66d9ef">new</span> HandlerRoutine(ConsoleCtrlCheck); -</span></span><span style="display:flex;"><span> SetConsoleCtrlHandler(_handler, <span style="color:#66d9ef">true</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = BuildStartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> WebApp.Start&lt;SelfHostStartup&gt;(startOptions); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">&#34;Press CTRL+C to stop it&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.WaitOne(); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> StartOptions BuildStartOptions() -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = <span style="color:#66d9ef">new</span> StartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted start options</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> startOptions; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>To prevent the HandlerRoutine instance from being recycled by the GC before the program exits, the HandlerRoutine must be static (as seen in the above example). This is important because if the handlerroutine is recycled before the application is finished, it will throw an error, as shown here:</p> -<pre tabindex="0"><code>A callback was made on a garbage collected delegate of type &#39;Program+HandlerRoutine::Invoke&#39;. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called. -</code></pre> + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. - diff --git a/public/categories/sre/page/1/index.html b/public/categories/sre/page/1/index.html index 058e2f81..f208631c 100644 --- a/public/categories/sre/page/1/index.html +++ b/public/categories/sre/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/sre/ - + http://localhost:1313/categories/sre/ + - + diff --git a/public/categories/synology/index.html b/public/categories/synology/index.html index d7118e2e..c4406e08 100644 --- a/public/categories/synology/index.html +++ b/public/categories/synology/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: Synology · GeekyRyan + - - -Synology - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,285 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Category: Synology

    - - - -
    -
    -
    -

    Backup Synology NAS to Azure Storage

    -
    -
    +
    +
    + © -
    - I’m not really a fan of photography. I don’t particularly enjoy the intracies of tuning a high-end DSLR camera. Nor am I a fan of being out in nature to photograph a fall sunrise (though, that does sound peaceful). However, I do take a lot of pictures with my phone (currently, a Pixel 6). Moreso now that I am a new father. I am protective of these photos. So much that I sync them automatically from my phone to two cloud storage providers. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-12-25-synology-backup-to-cloud/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - - + - - + + diff --git a/public/categories/synology/index.xml b/public/categories/synology/index.xml index 9b79cc8d..5c0f9931 100644 --- a/public/categories/synology/index.xml +++ b/public/categories/synology/index.xml @@ -2,48 +2,18 @@ Synology on GeekyRyan - https://rnemeth90.github.io/categories/synology/ - GeekyRyan (Synology) - Hugo -- gohugo.io - en-us + http://localhost:1313/categories/synology/ + Recent content in Synology on GeekyRyan + Hugo + en Tue, 27 Dec 2022 00:00:00 +0000 - - - - + Backup Synology NAS to Azure Storage - https://rnemeth90.github.io/posts/2022-12-25-synology-backup-to-cloud/ + http://localhost:1313/posts/2022-12-25-synology-backup-to-cloud/ Tue, 27 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-25-synology-backup-to-cloud/ - <p>I&rsquo;m not really a fan of photography. I don&rsquo;t particularly enjoy the intracies of tuning a high-end DSLR camera. Nor am I a fan of being out in nature to photograph a fall sunrise (though, that does sound peaceful). However, I do take a lot of pictures with my phone (currently, a Pixel 6). Moreso now that I am a new father. I am protective of these photos. So much that I sync them automatically from my phone to two cloud storage providers. I thought the other day, how painful it would be for either of these cloud storage providers to go offline. Though unlikely, anything is possible, right?</p> -<p>So, like any good engineer, I started looking for a solution for this concern. I have 2 Synology NAS devices here at my home. Calling a Synology a NAS is almost an insult. They are much more than that. Though they specialize in storage, they provide a plethora of apps that extend the functionality of the device. A Synology device can provide storage, email, DNS, media, etc. services though OEM and third-party apps. A single device can also link up with other devices to form a highly-available mesh of Synology services. Pretty neat for just a little black desktop box! Anyway, I&rsquo;m not a Synology salesman, so let&rsquo;s get back on track&hellip;</p> -<p>I wanted to be able to have a local copy of all of my photos (and other files) that are currently synced to the cloud. I then wanted to backup this local copy to another remote location (something like a 3-2-1 backup architecture, but not really&hellip;). Synology provides an app called Cloud Sync that can be used to sync files from a cloud storage provider like Google Photos/Drive or Microsoft OneDrive to a local device. They also provide another app called Hyper Backup that can be used to backup local files to remote storage, like an Azure Storage Account or Amazon S3 Bucket. By now, you probably get where this is going.</p> -<p>I&rsquo;m going to configure Cloud Sync to pull files down to my Synology and then use Hyper Backup to push a weekly backup to Azure Blob Storage. Let&rsquo;s dive in! -If you&rsquo;re following along, you&rsquo;ll need to install both of these apps. They are available via One-Click install in the Synology Package Center, so I won&rsquo;t cover the installation process. The setup is extremely simple as well, but I&rsquo;ll go over it just because.</p> -<p>We&rsquo;ll first setup Cloud Sync. Open Cloud Sync and click the &lsquo;+&rsquo; symbol to add a new account.</p> -<p>For my purposes, I&rsquo;m going to choose Microsoft OneDrive:</p> -<p><a href="https://rnemeth90.github.io/images/synology-cloud-sync-01.png"><img src="https://rnemeth90.github.io/images/synology-cloud-sync-01.png" alt=""></a></p> -<p>When prompted to authenticate, login to your OneDrive account. Then, configure the sync settings. You can create a name for the connection, add a local path in which to sync your files to, choose which remote folders/files to sync, the sync direction, a schedule, etc.</p> -<p><a href="https://rnemeth90.github.io/images/synology-cloud-sync-02.png"><img src="https://rnemeth90.github.io/images/synology-cloud-sync-02.png" alt=""></a></p> -<p>Click Next, and then finish the wizard. Simple.</p> -<p>Depending on the amount of files you have, you&rsquo;ll need to allow some time for your files to sync.</p> -<p>Now, we&rsquo;ll setup Hyper Backup to backup the files you sync&rsquo;d locally to remote storage. As stated previously, I&rsquo;ll be backing up my files to Azure Blob Storage. I have already created the Storage Account in Azure, and will not be covering that in this article.</p> -<p>Open Hyper Backup and click the &lsquo;+&rsquo; symbol in the lower left corner, and then click &lsquo;Data Backup Task&rsquo;. Then, choose &lsquo;Microsoft Azure&rsquo;:</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-01.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-01.png" alt=""></a> -<a href="https://rnemeth90.github.io/images/synology-hyper-backup-02.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-02.png" alt=""></a></p> -<p>On the next page, enter in your Storage Account info and then click Next. You can then choose which local folders on your Synology to backup:</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-03.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-03.png" alt=""></a></p> -<p>Click next and choose to backup application settings:</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-04.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-04.png" alt=""></a></p> -<p>On this page, we can configure the backup settings. Name the task, and configure your notification settings, schedule, compression, and encryption.</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-05.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-05.png" alt=""></a></p> -<p>On the last page, we configure our backup rotation settings. I am going to keep 31 days of backups, starting from the oldest backup. This means that at any given time I will have 31 days worth of backups in the storage account.</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-06.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-06.png" alt=""></a></p> -<p>That&rsquo;s all for configuring the backups! Very simple. Depending on how much data you have and your ISP, it may take a while to backup your files. If you configured notifications, you should receive a notification once the job is complete.</p> - + http://localhost:1313/posts/2022-12-25-synology-backup-to-cloud/ + I&rsquo;m not really a fan of photography. I don&rsquo;t particularly enjoy the intracies of tuning a high-end DSLR camera. Nor am I a fan of being out in nature to photograph a fall sunrise (though, that does sound peaceful). However, I do take a lot of pictures with my phone (currently, a Pixel 6). Moreso now that I am a new father. I am protective of these photos. So much that I sync them automatically from my phone to two cloud storage providers. - diff --git a/public/categories/synology/page/1/index.html b/public/categories/synology/page/1/index.html index 392740a5..59bc3fe7 100644 --- a/public/categories/synology/page/1/index.html +++ b/public/categories/synology/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/synology/ - + http://localhost:1313/categories/synology/ + - + diff --git a/public/categories/uncategorized/index.html b/public/categories/uncategorized/index.html index 2de41252..b3a97ce7 100644 --- a/public/categories/uncategorized/index.html +++ b/public/categories/uncategorized/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: Uncategorized · GeekyRyan + - + -Uncategorized - GeekyRyan - + + + - - - + + + + + + + + + - - - - - + + + + - - - - - - - - - - - - - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,818 +79,262 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - - -
    -
    - -

    Category: Uncategorized

    - - - -
    -
    -
    -

    Injecting multiple Kubernetes volumes to the same directory in a pod

    -
    - -
    - - -
    - We can inject configuration into containers using Kubernetes config maps and secrets. These objects can be consumed by a pod as environment variables, command-line arguments, or as configuration files mounted in a volume. For the subject of this article, we will focus on mounting multiple config maps/secrets into a single directory on a pod. -Mounting a configmap or secret in a Volume is relatively straightforward (for anyone familiar with Kubernetes primitives). -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Deploy Azure VMs Using Azure Devops CI/CD Pipeline

    -
    - -
    - - -
    - This article assumes that you have already created a pipeline in Azure Devops and have it linked to an Azure Devops repo. You will need to create a variable named $vmpassword and assign it the value stored in your key vault. -To create a release pipeline that will automatically create a VM (using the password stored in key vault for the local administrator account), do the following: -Create a new release pipeline 3. -
    - - -
    - Read more -
    - - - - - - -
    - -
    -
    -
    -

    Azure Devops &#8211; Self Hosted Agent Service Won&#8217;t Start &#8211; Incorrect Function

    -
    - -
    - - -
    - I setup a self hosted agent for Azure Devops this morning on Server 2012 R2 (legacy Visual Studio dependencies…) and found that I was unable to start the service. The error I received was “Error 1 Incorrect Function” when attempting to start the service in services.msc. -I was attempting to run the agent from within my user profile downloads folder. I originally was not aware the service would be running from this directory. -
    - - -
    - Read more -
    - - - - - - - -
    - -
    -
    -
    -

    Azure Tenant Maintenance &#8211; Purge Empty Resource Groups

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Category: Uncategorized +

    +
    + +
      -
      - This will be the first article in a series about maintaining Azure tenants and subscriptions. -If you currently, or have ever, worked in a large Azure environment, you know how easily resource creep can occur. Resource Groups, VM disks and network interfaces, network security groups, etc. can easily fall out of sight and be forgotten about. This isn’t a big concern for resources that are free of cost, like resource groups. -
      - - -
      - Read more -
      - - - - - - - - - -
    +
  • + 2022-04-30 + Injecting multiple Kubernetes volumes to the same directory in a pod +
  • -
    -
    -
    -

    Exam AZ-303: Microsoft Azure Architect Technologies Study Guide

    -
    - -
    - +
  • + 2022-01-14 + Deploy Azure VMs Using Azure Devops CI/CD Pipeline +
  • -
    - I recently passed the AZ-303 exam. Below are some of the resources I used to prepare for the exam. In addition to the links below, I also used Alan Rodrigues’ course on Udemy. https://www.udemy.com/course/az-102-azure-administrator-certification-transition/ The Udemy course and Microsoft Docs are enough to pass the exam. The course has some good practice exams and labs that align well with what you’ll see on the real exam regarding difficulty. I was scoring in the high 90’s on the Udemy exams. -
    +
  • + 2022-01-14 + Azure Devops &#8211; Self Hosted Agent Service Won&#8217;t Start &#8211; Incorrect Function +
  • +
  • + 2022-01-14 + Azure Tenant Maintenance &#8211; Purge Empty Resource Groups +
  • -
    - Read more -
    +
  • + 2020-12-16 + Exam AZ-303: Microsoft Azure Architect Technologies Study Guide +
  • +
  • + 2020-11-26 + Azure AD Sync &#8211; Set-MsolDirSyncEnabled : You cannot turn off Active Directory synchronization. +
  • +
  • + 2020-11-19 + Azure VM Scale Set &#8211; Get Instance IP Address +
  • - +
  • + 2020-11-17 + Azure Policy &#8211; Allowed Locations for Resource Deployment +
  • - - - -
    - -
    -
    -
    -

    Azure AD Sync &#8211; Set-MsolDirSyncEnabled : You cannot turn off Active Directory synchronization.

    -
    - -
    +
      + + -
      - I recently ran into a situation in my lab environment that required I resync all (2000+) user accounts to Azure AD. Though this sounds complex and daunting, its actually quite simple. T -The basic steps involve disabling sync, and then removing the user objects. This can all be done with two PowerShell commands: -1) Set-MsolDirSyncEnabled -EnableDirSync $false -2) Get-MsolUser -All | Remove-MsolUser -force -The account that you are currently running the commands as will not be removed. -
      + -
      - Read more -
      + +
    • 1
    • + + - - - - - -
    - -
    -
    -
    -

    Azure VM Scale Set &#8211; Get Instance IP Address

    -
    - -
    - - -
    - If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal. -There are a few options we have for retrieving information about a VMSS and its instances without using the Azure Portal. -
    + +
  • 2
  • + + -
    - Read more -
    + - + +
  • 3
  • + - - - - -
    + -
    -
    -
    -

    Azure Policy &#8211; Allowed Locations for Resource Deployment

    -
    - -
    - -
    - Azure Policy allows us to control what actions users can perform regarding creating and managing resources in Azure. We can define policies for naming standards, require that certain extensions be installed on virtual machines, audit various resources for certain configurations… the possibilities are endless. -In this article, well focus on defining what locations users can deploy resources in. To get started, login to the Azure Portal and search for “Policy”. -
    + +
  • 4
  • + + -
    - Read more -
    + - + +
  • 5
  • + - - - -
    - -
    -
    -
    -

    Replicate an Azure VM Image Between Regions

    -
    -
    +
    +
    + © -
    - Let’s say you have a VM in Azure North Central. You created this VM from a custom image that you maintain in an Azure image repository. Now, what if you wanted to create that same VM in Azure South Central, and use the same reference image? A standard image repository is limited to the region that it exists in. The answer here is to create a Shared Image Library, add the image to it, and then configure the image to replicate to other Azure regions. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - - -
    +
    +
    -
    - - - - - - -
    -
    - - - -
    -
    -
    -

    Reset GRUB/root Password for vCenter/PSC Appliance

    -
    - -
    + - -
    - In Redhat/Fedora/Cent, GRUB can be protected by running the grub-md5-crypt command and pasting the outputted password hash into the grub.conf file. vSphere 6.0 password protects grub by default. If you change the root password in the VAMI, the GRUB password is changed to match. If you do not change the root password, the GRUB password is “vmware”. -To reset the GRUB password, we need to boot into a Cent or Redhat live CD. -
    - - -
    - Read more -
    - - - + + + + - + + -
    - - - - https://rnemeth90.github.io/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ - Ryan + + -
    - - - - - - -
    -
    -
    - - - - - + + + + - - - + - - + + diff --git a/public/categories/uncategorized/index.xml b/public/categories/uncategorized/index.xml index 68a485e6..19d1fddb 100644 --- a/public/categories/uncategorized/index.xml +++ b/public/categories/uncategorized/index.xml @@ -2,1837 +2,347 @@ Uncategorized on GeekyRyan - https://rnemeth90.github.io/categories/uncategorized/ - GeekyRyan (Uncategorized) - Hugo -- gohugo.io - en-us + http://localhost:1313/categories/uncategorized/ + Recent content in Uncategorized on GeekyRyan + Hugo + en Sat, 30 Apr 2022 14:21:05 +0000 - - - - + Injecting multiple Kubernetes volumes to the same directory in a pod - https://rnemeth90.github.io/posts/2022-04-30-injecting-multiple-kubernetes-volumes-to-the-same-directory-in-a-pod/ + http://localhost:1313/posts/2022-04-30-injecting-multiple-kubernetes-volumes-to-the-same-directory-in-a-pod/ Sat, 30 Apr 2022 14:21:05 +0000 - - https://rnemeth90.github.io/posts/2022-04-30-injecting-multiple-kubernetes-volumes-to-the-same-directory-in-a-pod/ - <p>We can inject configuration into containers using Kubernetes config maps and secrets. These objects can be consumed by a pod as environment variables, command-line arguments, or as configuration files mounted in a volume. For the subject of this article, we will focus on mounting multiple config maps/secrets into a single directory on a pod.</p> -<p>Mounting a configmap or secret in a Volume is relatively straightforward (for anyone familiar with Kubernetes primitives). Take for example the following deployment definition:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ConfigMap</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">application.properties</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> greeting=Hello -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> name=World</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>--- -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Secret</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-credentials</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">credentials.properties</span>: <span style="color:#ae81ff">&lt;base64 goes here&gt;</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">type</span>: <span style="color:#ae81ff">Opaque</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>--- -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Deployment</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">matchLabels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">template</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">busybox:latest</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">command</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">/bin/sh</span> -</span></span><span style="display:flex;"><span> - -<span style="color:#ae81ff">c</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">sleep 5000</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/config/application.properties</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readOnly</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-credentials-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/config/credentials.properties</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readOnly</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">configMap</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-credentials-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">secret</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">secretName</span>: <span style="color:#ae81ff">hello-world-credentials</span> -</span></span></code></pre></div><p>When this deployment is created, we see two directories are created in this pod (one for the configMap, and one for the secret). How can we mount these as two <em>files</em> in the ‘config’ directory, rather than two individual directories?</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/04/image.png"></a></p> -<p>The ~VolumeMounts~ directive within the container spec of the deployment has an optional (less-known) parameter named ‘subPath’. By using this parameter, we can mount a configMap and secret in the same directory within a pod.</p> -<p>Let’s focus on the following deployment spec:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ConfigMap</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">application.properties</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> greeting=Hello -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> name=World</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>--- -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Secret</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-credentials</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">credentials.properties</span>: <span style="color:#ae81ff">&lt;base64 goes here&gt;</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">type</span>: <span style="color:#ae81ff">Opaque</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>--- -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Deployment</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">matchLabels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">template</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">busybox:latest</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">command</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">/bin/sh</span> -</span></span><span style="display:flex;"><span> - -<span style="color:#ae81ff">c</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">sleep 5000</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/config/application.properties</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">subPath</span>: <span style="color:#ae81ff">application.properties</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readOnly</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-credentials-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/config/credentials.properties</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">subPath</span>: <span style="color:#ae81ff">credentials.properties</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readOnly</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">configMap</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-credentials-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">secret</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">secretName</span>: <span style="color:#ae81ff">hello-world-credentials</span> -</span></span></code></pre></div><p>Now, if we deploy this, we can see that we have two files in the ‘config’ directory of the pod, rather than a subdirectory for each config/secret:</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/04/image-1.png"></a></p> -<p>In this example, the key application.properties from the configuration map will be mounted to a file with the same name under /config/, and the secret value credentials.properties will be mounted to a second file under that directory. Both files will be read-only to the application.</p> - + http://localhost:1313/posts/2022-04-30-injecting-multiple-kubernetes-volumes-to-the-same-directory-in-a-pod/ + We can inject configuration into containers using Kubernetes config maps and secrets. These objects can be consumed by a pod as environment variables, command-line arguments, or as configuration files mounted in a volume. For the subject of this article, we will focus on mounting multiple config maps/secrets into a single directory on a pod. Mounting a configmap or secret in a Volume is relatively straightforward (for anyone familiar with Kubernetes primitives). - Deploy Azure VMs Using Azure Devops CI/CD Pipeline - https://rnemeth90.github.io/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ + http://localhost:1313/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ Fri, 14 Jan 2022 18:46:35 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ - <p>This article assumes that you have already created a pipeline in Azure Devops and have it linked to an Azure Devops repo. You will need to create a variable named $vmpassword and assign it the value stored in your key vault.</p> -<p>To create a release pipeline that will automatically create a VM (using the password stored in key vault for the local administrator account), do the following:</p> -<ol> -<li>Create a new release pipeline</li> -</ol> -<p><img src="https://www.rnemeth90.github.io/content/images/2021/01/image-13.png" alt=""></p> -<p>3. In the “select a template” box, choose “Empty Job”<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-14.png" alt=""></p> -<p>4. Select “Tasks” in the navigation bar, and then select the appropriate stage. For simplicities sake, we will be using 1 stage within this release.<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-15.png" alt=""></p> -<p>5. Click on the “+” in the Agent job bar, and then in the “Add tasks” section, type in “Key Vault”. Click “Azure Key Vault” and then click “Add”. <img src="https://www.rnemeth90.github.io/content/images/2021/01/image-16.png" alt=""></p> -<p>6. Click on the “Azure Key Vault:” task to configure it. Select your subscription, Key Vault, and the secrets filter. You can also create the $vmpassword variable as a variable within your devops project, rather than assigning it as a secret filter for the release. <img src="https://www.rnemeth90.github.io/content/images/2021/01/image-20.png" alt=""></p> -<p>7. In your Key Vault, you need to grant the devops account access to the Key Vault. To do this, go to your Key Vault and create a new access policy. This policy will be assigned to a service principal that is being used by your Azure Devops project. To find the ID of this service principal, go to your project settings, and under “Pipelines”, click on “Service Connections”. Then select the service connection that resembles your subscription. After doing this, click “Manage Service Principal”. In the service principal window, click “Manifest” and then find the “name” tag within the JSON.<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-19.png" alt=""></p> -<p>8. Now go back to your key vault, and assign an access policy for this service principal. Grant the principal read and list for secrets.</p> -<p>9. Add another agent job for the task (see step 6) and search for “azure cli”. Click on “Add” for Azure CLI. Configure the settings for this job as below:<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-18.png" alt=""></p> -<p>10. Save and run your pipeline. Give it some time to complete, and go take a look at your newly created VM. This is just a very simple example of creating a server as part of a CI/CD pipeline. You can then deploy your code to it, run some tests, destroy them VM, etc. Completely automated.<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-21.png" alt=""></p> - + http://localhost:1313/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ + This article assumes that you have already created a pipeline in Azure Devops and have it linked to an Azure Devops repo. You will need to create a variable named $vmpassword and assign it the value stored in your key vault. To create a release pipeline that will automatically create a VM (using the password stored in key vault for the local administrator account), do the following: Create a new release pipeline 3. - Azure Devops &#8211; Self Hosted Agent Service Won&#8217;t Start &#8211; Incorrect Function - https://rnemeth90.github.io/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ + http://localhost:1313/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ Fri, 14 Jan 2022 18:45:00 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ - <p>I setup a self hosted agent for Azure Devops this morning on Server 2012 R2 (legacy Visual Studio dependencies…) and found that I was unable to start the service. The error I received was “Error 1 Incorrect Function” when attempting to start the service in services.msc.</p> -<p>I was attempting to run the agent from within my user profile downloads folder. I originally was not aware the service would be running from this directory. I thought it would copy its binary files to program files directory or programdata, like 99% of all other apps. The service installs and attempts to run itself as the “network service” authority. This account does not have permission to a user profile folder by default, and the installation script is not able to grant it permission for some reason (I didn’t investigate this further). I removed the agent, moved the installation files to the root of c:, and then reinstalled. The agent service is now able to start successfully.</p> - + http://localhost:1313/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ + I setup a self hosted agent for Azure Devops this morning on Server 2012 R2 (legacy Visual Studio dependencies…) and found that I was unable to start the service. The error I received was “Error 1 Incorrect Function” when attempting to start the service in services.msc. I was attempting to run the agent from within my user profile downloads folder. I originally was not aware the service would be running from this directory. - Azure Tenant Maintenance &#8211; Purge Empty Resource Groups - https://rnemeth90.github.io/posts/2022-01-14-azure-tenant-maintenance-purge-empty-resource-groups/ + http://localhost:1313/posts/2022-01-14-azure-tenant-maintenance-purge-empty-resource-groups/ Fri, 14 Jan 2022 18:43:35 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-azure-tenant-maintenance-purge-empty-resource-groups/ - <p>This will be the first article in a series about maintaining Azure tenants and subscriptions.</p> -<p>If you currently, or have ever, worked in a large Azure environment, you know how easily resource creep can occur. Resource Groups, VM disks and network interfaces, network security groups, etc. can easily fall out of sight and be forgotten about. This isn’t a big concern for resources that are free of cost, like resource groups. However, if you delete several virtual machines, the disks that were attached to those virtual machines linger, and you continue to pay the cost of storing them.</p> -<p>In this blog post, we will review a script I created for removing empty resource groups. We will then add this script to an Azure Automation Account and link it to a schedule. We will assume you already have an Azure Automation Account in existence, and the Automation Account has a credential object named ‘AzureRunAsConnection’.</p> -<p>To get started, you can download the script here:</p> -<p><a href="https://github.com/rnemeth90/azure-automation/blob/master/clean-empty-resource-groups.ps1">https://github.com/rnemeth90/azure-automation/blob/master/clean-empty-resource-groups.ps1</a></p> -<p>This particular runbook will require that the “AZ.Resources” module be loaded in the Automation Account. To import this module, go to your automation account and then click on “Modules” under “Shared Resources”. Then, click on “Browse Gallery”.</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image.png"></a></p> -<p>In the search bar, type in “Az.resources”, then click on the module and click “Import”. If you see a message like this, you will need to add any modules that az.resources depends on before importing it.</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image-1.png"></a></p> -<p>You can go back and add those modules using the same process, and then attempt to import the “Az.resources” module again. Importing these modules may take several minutes. In my experience, it takes around 10-15 minutes.</p> -<p>Once these modules are imported you can import the PowerShell runbook you downloaded earlier from Github. To do that, browse to the Runbooks section of your Automation Account and then click “Import a Runbook”:</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image-2.png"></a></p> -<p>In the context menu that appears, browse to the runbook and upload it, choose “PowerShell” as the runbook type, and then click Create:</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image-3.png"></a></p> -<p>In the Editor Pane, click on “Test Pane”. This will bring you to the Test Pane for the runbook. This will allow you to test the runbook before running it in your environment. Click “Start” in the Test Pane. This particular runbook will output to screen any changes it will make, so you can see the results here.</p> -<p>As you can see here, the runbook did find some empty resource groups, but did not remove them:</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image-4.png"></a></p> -<p>This is because we have a variable in the runbook that controls whether or not any write/update actions will be taken on resources. Click the X in the upper right corner to go back to the editor, and change the value in the screenshot below from “0” to “1”.</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image-8.png"></a></p> -<p>If you’d like, you can test the runbook again, or you can click “Publish” to publish it to your Automation Account. Once it’s published, you can link it to a schedule so that it runs automatically.</p> -<p>Click “Publish”:</p> -<p>&lt;<a href="https://www.rnemeth90.github.io/content/images/2021/06/image-9.png"></a></p> -<p>Then, on the Runbook page, click “Schedules”, and then “Add a schedule”:</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image-10.png"></a></p> -<p>Fill out the wizard that pops up to create a schedule and link it to your workbook. This concludes this article.</p> -<p>In the next post, we will take a look at removing empty resource groups automatically. Stay tuned.</p> - + http://localhost:1313/posts/2022-01-14-azure-tenant-maintenance-purge-empty-resource-groups/ + This will be the first article in a series about maintaining Azure tenants and subscriptions. If you currently, or have ever, worked in a large Azure environment, you know how easily resource creep can occur. Resource Groups, VM disks and network interfaces, network security groups, etc. can easily fall out of sight and be forgotten about. This isn’t a big concern for resources that are free of cost, like resource groups. - Exam AZ-303: Microsoft Azure Architect Technologies Study Guide - https://rnemeth90.github.io/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ + http://localhost:1313/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ Wed, 16 Dec 2020 14:44:00 +0000 - - https://rnemeth90.github.io/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ - <p><span style="font-family: arial;">I recently passed the AZ-303 exam. Below are some of the resources I used to prepare for the exam. In addition to the links below, I also used Alan Rodrigues’ course on Udemy. </span></p> -<p><span style="font-family: arial;"><a href="https://www.udemy.com/course/az-102-azure-administrator-certification-transition/">https://www.udemy.com/course/az-102-azure-administrator-certification-transition/</a> -</span></p> -<p><span style="font-family: arial;">The Udemy course and Microsoft Docs are enough to pass the exam. The course has some good practice exams and labs that align well with what you’ll see on the real exam regarding difficulty. I was scoring in the high 90’s on the Udemy exams. On the real exam, my score was 923. So, I think, if you comprehend the material well, and get high scores on Udemy practice exams, you’ll do well on the real exam.</span></p> -<p><span style="font-family: arial;">Just wanted to share my experience, hopefully it helps.</span></p> -<p><strong><u><span style="font-size: large;">Implement and Monitor an Azure Infrastructure (50-55%)</span></u></strong></p> -<p><span style="font-size: medium;"><strong>Implement cloud infrastructure monitoring</strong></span></p> -<ul> -<li> -<p>monitor security</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/security-center/security-center-introduction">What is Azure Security Center?</a></p> -</li> -<li> -<p>monitor performance</p> -</li> -<li> -<p>configure diagnostic settings on resources</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/diagnostic-settings">Create diagnostic settings to send platform logs and metrics to different destinations</a></p> -</li> -<li> -<p>create a performance baseline for resources</p> -</li> -<li> -<p><a href="https://cloudacademy.com/course/analyzing-resource-utilization-azure/resource-baseline/">Analyzing Resource Utilization on Azure</a></p> -</li> -<li> -<p>monitor for unused resources</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cost-management-billing/costs/quick-acm-cost-analysis?tabs=azure-portal">Quickstart: Explore and analyze costs with cost analysis</a></p> -</li> -<li> -<p>monitor performance capacity</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/insights/vminsights-performance">How to chart performance with Azure Monitor for VMs</a></p> -</li> -<li> -<p>visualize diagnostics data using Azure Monitor</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/workbooks-overview">Azure Monitor Workbooks</a></p> -</li> -<li> -<p>monitor health and availability</p> -</li> -<li> -<p>monitor networking</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/insights/network-insights-overview">Azure Monitor for Networks</a></p> -</li> -<li> -<p>monitor service health</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/service-health/service-health-overview">Service Health overview</a></p> -</li> -<li> -<p>monitor cost</p> -</li> -<li> -<p>monitor spend</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cost-management-billing/costs/quick-acm-cost-analysis?tabs=azure-portal">Quickstart: Explore and analyze costs with cost analysis</a></p> -</li> -<li> -<p>report on spend</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cost-management-billing/understand/download-azure-invoice">View and download your Microsoft Azure invoice</a></p> -</li> -<li> -<p>configure advanced logging</p> -</li> -<li> -<p>implement and configure Azure Monitor insights, including App Insights, Networks, Containers</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/monitor-reference">What is monitored by Azure Monitor?</a></p> -</li> -<li> -<p>configure a Log Analytics workspace</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/learn/quick-create-workspace">Create a Log Analytics workspace in the Azure portal</a></p> -</li> -<li> -<p>configure logging for workloads</p> -</li> -<li> -<p>initiate automated responses by using Action Groups</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/action-groups">Create and manage action groups in the Azure portal</a></p> -</li> -<li> -<p>configure and manage advanced alerts</p> -</li> -<li> -<p>collect alerts and metrics across multiple subscriptions</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/alerts-metric">Create, view, and manage metric alerts using Azure Monitor</a></p> -</li> -<li> -<p>view Alerts in Azure Monitor logs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/alerts-activity-log">Create, view, and manage activity log alerts by using Azure Monitor</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement storage accounts</span></strong></p> -<ul> -<li> -<p>select storage account options based on a use case</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-account-create?tabs=azure-portal">Create a storage account</a></p> -</li> -<li> -<p>configure Azure Files and blob storage</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/files/storage-how-to-create-file-share?tabs=azure-portal">Create an Azure file share</a></p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-portal">Quickstart: Upload, download, and list blobs with the Azure portal</a></p> -</li> -<li> -<p>configure network access to the storage account</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-network-security">Configure Azure Storage firewalls and virtual networks</a></p> -</li> -<li> -<p>implement Shared Access Signatures and access policies</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-sas-overview">Grant limited access to Azure Storage resources using shared access signatures (SAS)</a></p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/rest/api/storageservices/define-stored-access-policy">Define a stored access policy</a></p> -</li> -<li> -<p>implement Azure AD authentication for storage</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-auth-aad">Authorize access to blobs and queues using Azure Active Directory</a></p> -</li> -<li> -<p>manage access keys</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-account-keys-manage?tabs=azure-portal">Manage storage account access keys</a></p> -</li> -<li> -<p>implement Azure storage replication</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/blobs/object-replication-configure?tabs=portal">Configure object replication for block blobs</a></p> -</li> -<li> -<p>implement Azure storage account failover</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-disaster-recovery-guidance">Disaster recovery and storage account failover</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement VMs for Windows and Linux</span></strong></p> -<ul> -<li> -<p>configure High Availability</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/manage-availability">Manage the availability of Linux virtual machines</a></p> -</li> -<li> -<p>configure storage for VMs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/managed-disks-overview">Introduction to Azure managed disks</a></p> -</li> -<li> -<p>select virtual machine size</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/sizes">Sizes for virtual machines in Azure</a></p> -</li> -<li> -<p>implement Azure Dedicated Hosts</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/dedicated-hosts-portal">Deploy VMs and scale sets to dedicated hosts using the portal</a></p> -</li> -<li> -<p>deploy and configure scale sets</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machine-scale-sets/quick-create-portal">Quickstart: Create a virtual machine scale set in the Azure portal</a></p> -</li> -<li> -<p>configure Azure Disk Encryption</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/windows/disk-encryption-overview">Azure Disk Encryption for Windows VMs</a></p> -</li> -</ul> -<p><span style="font-size: medium;"><strong>Automate deployment and configuration of resources</strong></span></p> -<ul> -<li> -<p>save a deployment as an Azure Resource Manager template</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/export-template-portal">Single and multi-resource export to a template in Azure portal</a></p> -</li> -<li> -<p>modify Azure Resource Manager template</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/overview">What are ARM templates?</a></p> -</li> -<li> -<p>evaluate location of new resources</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/view-activity-logs">View activity logs to monitor actions on resources</a></p> -</li> -<li> -<p>configure a virtual disk template</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/windows/capture-image-resource">Create a managed image of a generalized VM in Azure</a></p> -</li> -<li> -<p>deploy from a template</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/deploy-vms-from-vhd-templates/">Deploy Azure virtual machines from VHD templates</a></p> -</li> -<li> -<p>manage a template library</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/shared-image-galleries">Shared Image Galleries overview</a></p> -</li> -<li> -<p>create and execute an automation runbook</p> -</li> -<li> -<p><a href="https://azure.microsoft.com/en-us/blog/azure-automation-runbook-management/">Getting Started With Azure Automation – Runbook Management</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement virtual networking</span></strong></p> -<ul> -<li> -<p>implement VNet to VNet connections</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/vpn-gateway/vpn-gateway-howto-vnet-vnet-resource-manager-portal">Configure a VNet-to-VNet VPN gateway connection by using the Azure portal</a></p> -</li> -<li> -<p>implement VNet peering</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-peering-overview">Virtual network peering</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement Azure Active Directory</span></strong></p> -<ul> -<li> -<p>add custom domains</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/add-custom-domain">Add your custom domain name using the Azure Active Directory portal</a></p> -</li> -<li> -<p>configure Azure AD Identity Protection</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/identity-protection/overview-identity-protection">What is Identity Protection?</a></p> -</li> -<li> -<p>implement self-service password reset</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/tutorial-enable-sspr">Tutorial: Enable users to unlock their account or reset passwords using Azure Active Directory self-service password reset</a></p> -</li> -<li> -<p>implement Conditional Access including MFA</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/conditional-access/howto-conditional-access-policy-all-users-mfa">Conditional Access: Require MFA for all users</a></p> -</li> -<li> -<p>configure user accounts for MFA</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-userstates">Enable per-user Azure AD Multi-Factor Authentication to secure sign-in events</a></p> -</li> -<li> -<p>configure fraud alerts</p> -</li> -<li> -<p><a href="Enable%20per-user%20Azure%20AD%20Multi-Factor%20Authentication%20to%20secure%20sign-in%20events">Fraud alert</a></p> -</li> -<li> -<p>configure bypass options</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-server-settings#one-time-bypass">One-time bypass</a></p> -</li> -<li> -<p>configure Trusted IPs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-mfasettings#trusted-ips">Trusted IPs</a></p> -</li> -<li> -<p>configure verification methods</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/concept-sspr-howitworks#authentication-methods">Authentication methods</a></p> -</li> -<li> -<p>implement and manage guest accounts</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/external-identities/b2b-quickstart-add-guest-users-portal">Quickstart: Add guest users to your directory in the Azure portal</a></p> -</li> -<li> -<p>manage multiple directories</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/enterprise-users/licensing-directory-independence">Understand how multiple Azure Active Directory organizations interact</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement and manage hybrid identities</span></strong></p> -<ul> -<li> -<p>install and configure Azure AD Connect</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-install-express">Getting started with Azure AD Connect using express settings</a></p> -</li> -<li> -<p>identity synchronization options</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/plan-connect-user-signin">Azure AD Connect user sign-in options</a></p> -</li> -<li> -<p>configure and manage password sync and password writeback</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/tutorial-enable-sspr-writeback">Tutorial: Enable Azure Active Directory self-service password reset writeback to an on-premises environment</a></p> -</li> -<li> -<p>configure single sign-on</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-sso-quick-start">Azure Active Directory Seamless Single Sign-On: Quickstart</a></p> -</li> -<li> -<p>use Azure AD Connect Health</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/whatis-azure-ad-connect#what-is-azure-ad-connect-health">What is Azure AD Connect Health?</a></p> -</li> -</ul> -<p><strong><u><span style="font-size: large;">Implement Management and Security Solutions (25-30%)</span></u></strong></p> -<p><span style="font-size: medium;"><strong>Manage workloads in Azure</strong></span></p> -<ul> -<li> -<p>migrate workloads using Azure Migrate</p> -</li> -<li> -<p>assess infrastructure</p> -</li> -<li> -<p>select a migration method</p> -</li> -<li> -<p>prepare the on-premises for migration</p> -</li> -<li> -<p>recommend target infrastructure</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/migrate/tutorial-migrate-hyper-v">Migrate Hyper-V VMs to Azure</a></p> -</li> -<li> -<p>implement Azure Backup for VMs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/backup/backup-azure-vms-first-look-arm">Back up an Azure VM from the VM settings</a></p> -</li> -<li> -<p>implement disaster recovery</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/site-recovery/azure-to-azure-tutorial-enable-replication">Tutorial: Set up disaster recovery for Azure VMs</a></p> -</li> -<li> -<p>implement Azure Update Management</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/automation/update-management/enable-from-vm">Enable Update Management for an Azure VM</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement load balancing and network security</span></strong></p> -<ul> -<li> -<p>implement Azure Load Balancer</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/load-balancer/load-balancer-overview">What is Azure Load Balancer?</a></p> -</li> -<li> -<p>implement an application gateway</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/application-gateway/overview">What is Azure Application Gateway?</a></p> -</li> -<li> -<p>implement a Web Application Firewall</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/web-application-firewall/overview">What is Azure Web Application Firewall?</a></p> -</li> -<li> -<p>implement Azure Firewall</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/firewall/overview">What is Azure Firewall?</a></p> -</li> -<li> -<p>implement the Azure Front Door Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/frontdoor/quickstart-create-front-door">Quickstart: Create a Front Door for a highly available global web application</a></p> -</li> -<li> -<p>implement Azure Traffic Manager</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/traffic-manager/traffic-manager-overview">What is Traffic Manager?</a></p> -</li> -<li> -<p>implement Network Security Groups and Application Security Groups</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-network/network-security-groups-overview">Network security groups</a></p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-network/application-security-groups">Application security groups</a></p> -</li> -<li> -<p>implement Bastion</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/bastion/">Azure Bastion documentation</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement and manage Azure governance solutions</span></strong></p> -<ul> -<li> -<p>create and manage hierarchical structure that contains management groups</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/governance/management-groups/overview">What are Azure management groups?</a></p> -</li> -<li> -<p>subscriptions and resource groups</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-setup-guide/organize-resources?tabs=AzureManagementGroupsAndHierarchy">Organize your Azure resources effectively</a></p> -</li> -<li> -<p>assign RBAC roles</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal">Add or remove Azure role assignments using the Azure portal</a></p> -</li> -<li> -<p>create a custom RBAC role</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/custom-roles">Azure custom roles</a></p> -</li> -<li> -<p>configure access to Azure resources by assigning roles</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal">Add or remove Azure role assignments using the Azure portal</a></p> -</li> -<li> -<p>configure management access to Azure</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/manage-subscription-access-azure-rbac/">Manage access to an Azure subscription by using Azure role-based access control (RBAC)</a></p> -</li> -<li> -<p>interpret effective permissions</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/check-access">Quickstart: Check access for a user to Azure resources</a></p> -</li> -<li> -<p>set up and perform an access review</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/governance/access-reviews-overview">What are Azure AD access reviews?</a></p> -</li> -<li> -<p>implement and configure an Azure Policy</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/governance/policy/assign-policy-portal">Quickstart: Create a policy assignment to identify non-compliant resources</a></p> -</li> -<li> -<p>implement and configure an Azure Blueprint</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/governance/blueprints/overview">What is Azure Blueprints?</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Manage security for applications</span></strong></p> -<ul> -<li> -<p>implement and configure KeyVault</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/configure-and-manage-azure-key-vault/">Configure and manage secrets in Azure Key Vault</a></p> -</li> -<li> -<p>implement and configure Managed Identities</p> -</li> -<li> -<p><a href="https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=18fbca16-2224-45f6-85b0-f7bf2b39b3f3&amp;nonce=ef221978-b465-49a1-9226-e8a0e4d25480&amp;prompt=none&amp;redirect_uri=https%3A%2F%2Fdocs.microsoft.com%2F_themes%2Fdocs.theme%2Fmaster%2Fen-us%2F_themes%2Fglobal%2Fsign-in.html&amp;response_mode=fragment&amp;response_type=id_token&amp;scope=openid%20profile&amp;sso_reload=true&amp;state=silent%3A%2F%2Fhttps%3A%2F%2Fdocs.microsoft.com&amp;fromOrigin=https%3A%2F%2Fdocs.microsoft.com&amp;iframe-request-id=685d3411-99a9-4f94-81e4-d9b8af575600">What are managed identities for Azure resources?</a></p> -</li> -<li> -<p>register and manage applications in Azure AD</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app">Quickstart: Register an application with the Microsoft identity platform</a></p> -</li> -</ul> -<p><strong><u><span style="font-size: large;">Implement Solutions for Apps (10-15%)</span></u></strong></p> -<p><strong><span style="font-size: medium;">Implement an application infrastructure</span></strong></p> -<ul> -<li> -<p>create and configure Azure App Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/quickstart-dotnetcore?tabs=netcore31&amp;pivots=platform-linux">Quickstart: Create an ASP.NET Core web app in Azure</a></p> -</li> -<li> -<p>create an App Service Web App for Containers</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/deploy-run-container-app-service/">Deploy and run a containerized web app with Azure App Service</a></p> -</li> -<li> -<p>create and configure an App Service plan</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/app-service-plan-manage">Manage an App Service plan in Azure</a></p> -</li> -<li> -<p>configure an App Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/configure-common">Configure an App Service app in the Azure portal</a></p> -</li> -<li> -<p>configure networking for an App Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/web-sites-integrate-with-vnet">Integrate your app with an Azure virtual network</a></p> -</li> -<li> -<p>create and manage deployment slots</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/deploy-staging-slots">Set up staging environments in Azure App Service</a></p> -</li> -<li> -<p>implement Logic Apps</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/logic-apps/quickstart-create-first-logic-app-workflow">Quickstart: Create your first Logic Apps workflow – Azure portal</a></p> -</li> -<li> -<p>implement Azure Functions</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-azure-function">Create your first function in the Azure portal</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement container-based applications </span></strong></p> -<ul> -<li> -<p>create a container image</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/container-registry/container-registry-quickstart-task-cli">Quickstart: Build and run a container image using Azure Container Registry Tasks</a></p> -</li> -<li> -<p>configure Azure Kubernetes Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/aks/kubernetes-walkthrough-portal">Quickstart: Deploy an Azure Kubernetes Service (AKS) cluster using the Azure portal</a></p> -</li> -<li> -<p>publish and automate image deployment to the Azure Container Registry</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/container-instances/container-instances-using-azure-container-registry">Deploy to Azure Container Instances from Azure Container Registry</a></p> -</li> -<li> -<p>publish a solution on an Azure Container Instance</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/container-instances/container-instances-quickstart-portal">Quickstart: Deploy a container instance in Azure using the Azure portal</a></p> -</li> -</ul> -<p><strong><u>Implement and Manage Data Platforms (10-15%)</u></strong></p> -<p><strong><span style="font-size: medium;">Implement NoSQL databases</span></strong></p> -<ul> -<li> -<p>configure storage account tables</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/tables/table-storage-quickstart-portal">Quickstart: Create an Azure Storage table in the Azure portal</a></p> -</li> -<li> -<p>select appropriate CosmosDB APIs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/choose-api-for-cosmos-db/">Choose the appropriate API for Azure Cosmos DB</a></p> -</li> -<li> -<p>set up replicas in CosmosDB</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cosmos-db/distribute-data-globally">Distribute your data globally with Azure Cosmos DB</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement Azure SQL databases</span></strong></p> -<ul> -<li> -<p>configure Azure SQL database settings</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-sql/database/single-database-create-quickstart?tabs=azure-portal">Quickstart: Create an Azure SQL Database single database</a></p> -</li> -<li> -<p>implement Azure SQL Database managed instances</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-sql/managed-instance/sql-managed-instance-paas-overview">What is Azure SQL Managed Instance?</a></p> -</li> -<li> -<p>configure HA for an Azure SQL database</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-sql/database/high-availability-sla">High availability for Azure SQL Database and SQL Managed Instance</a></p> -</li> -<li> -<p>publish an Azure SQL database</p> -</li> -</ul> - + http://localhost:1313/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ + I recently passed the AZ-303 exam. Below are some of the resources I used to prepare for the exam. In addition to the links below, I also used Alan Rodrigues’ course on Udemy. https://www.udemy.com/course/az-102-azure-administrator-certification-transition/ The Udemy course and Microsoft Docs are enough to pass the exam. The course has some good practice exams and labs that align well with what you’ll see on the real exam regarding difficulty. I was scoring in the high 90’s on the Udemy exams. - Azure AD Sync &#8211; Set-MsolDirSyncEnabled : You cannot turn off Active Directory synchronization. - https://rnemeth90.github.io/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ + http://localhost:1313/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ Thu, 26 Nov 2020 16:31:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ - <p>I recently ran into a situation in my lab environment that required I resync all (2000+) user accounts to Azure AD. Though this sounds complex and daunting, its actually quite simple. T</p> -<p>The basic steps involve disabling sync, and then removing the user objects. This can all be done with two PowerShell commands:</p> -<p>1) Set-MsolDirSyncEnabled -EnableDirSync $false</p> -<p><a href="https://lh3.googleusercontent.com/-rGK18FXw7ns/X7_WthQR0CI/AAAAAAAAyCM/gg7MsY2fcVIcWMMbvxYzPpbpPyKwgHP8ACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image.png" alt=""></a></p> -<p>2) Get-MsolUser -All | Remove-MsolUser -force</p> -<p><a href="https://lh3.googleusercontent.com/-miyfN7OISGo/X7_WzDCc6iI/AAAAAAAAyCQ/PtHURTTVMQ4uypzO7L1UaLfyEs0fpYGdACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-1.png" alt=""></a></p> -<p>The account that you are currently running the commands as will not be removed.</p> -<p>To enable Azure AD Sync, you simply reverse the boolean operation on the Set-MsolDirSyncEnabled cmdlet above. However, I ran into an issue when trying to enable Azure AD Sync.</p> -<p><a href="https://lh3.googleusercontent.com/-R1TPVgYaEBE/X7_XM5_ljKI/AAAAAAAAyCY/VIJZnlgNEPQbhL9p3D0J3XsekBrGiNS3QCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-2.png" alt=""></a></p> -<p>After some research, it turns out you must wait a period of time (up to 12 hours in some cases) before you can make a second change to the Azure AD Sync status. This error simply means that we made a recent change to Azure AD Sync, and we must wait before making another change. To prove this, there is a “DirectorySynchronizationStatus” member for the Get-MsolCompanyInformation cmdlet. If we take a look at this member, we can see the status is “PendingDisabled”.</p> -<p><a href="https://lh3.googleusercontent.com/-0OBwKDDD5xQ/X7_X1bBxXjI/AAAAAAAAyCk/FyRlaMpCDT4aBe08TL_8sLiwUBnHkcPJQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-3.png" alt=""></a></p> -<p>Check the status of this periodically over the next 12 hours or so, and once it says “Enabled” or “Disabled”, you should be able to change the state once more.</p> - + http://localhost:1313/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ + I recently ran into a situation in my lab environment that required I resync all (2000+) user accounts to Azure AD. Though this sounds complex and daunting, its actually quite simple. T The basic steps involve disabling sync, and then removing the user objects. This can all be done with two PowerShell commands: 1) Set-MsolDirSyncEnabled -EnableDirSync $false 2) Get-MsolUser -All | Remove-MsolUser -force The account that you are currently running the commands as will not be removed. - Azure VM Scale Set &#8211; Get Instance IP Address - https://rnemeth90.github.io/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ + http://localhost:1313/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ Thu, 19 Nov 2020 18:07:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ - <p>If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal.</p> -<p>There are a few options we have for retrieving information about a VMSS and its instances without using the Azure Portal. We can use PowerShell or the Azure CLI. Being that I am constantly flipping between Windows and Linux, I will detail both here.</p> -<p>You will need to have the AZ module installed. To install this module, simple open PowerShell (as admin) and type in “Install-Module -Name az”. To get the IP address of the instances within a scale set, use the following script:</p> -<p><a href="https://github.com/rnemeth90/Get-VmssInstanceIpAddress">https://github.com/rnemeth90/Get-VmssInstanceIpAddress</a></p> -<p>You can also use the Azure CLI to obtain individual instance IP addresses. This method is much simpler than PowerShell, and only requires one line of code:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>az vmss nic list –resource-group myResourceGroup –vmss-name myVmss | grep –w “privateIpAddress” -</span></span></code></pre></div> + http://localhost:1313/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ + If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal. There are a few options we have for retrieving information about a VMSS and its instances without using the Azure Portal. - Azure Policy &#8211; Allowed Locations for Resource Deployment - https://rnemeth90.github.io/posts/2020-11-17-azure-policy-allowed-locations-for/ + http://localhost:1313/posts/2020-11-17-azure-policy-allowed-locations-for/ Tue, 17 Nov 2020 17:52:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-17-azure-policy-allowed-locations-for/ - <p>Azure Policy allows us to control what actions users can perform regarding creating and managing resources in Azure. We can define policies for naming standards, require that certain extensions be installed on virtual machines, audit various resources for certain configurations… the possibilities are endless.</p> -<p>In this article, well focus on defining what locations users can deploy resources in. To get started, login to the Azure Portal and search for “Policy”.</p> -<p><a href="https://lh3.googleusercontent.com/-7ao7r-Xj5Kk/X7QNKSrY3AI/AAAAAAAAx-8/xIUtw-pRL20pSMxsOaGUwnk-9XHSpup9ACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-4.png" alt=""></a></p> -<p>Click on “Definitions”. Here you will find several built-in definitions that can be applied to your resources. Definitions are a json template containing the logic for what you want to accomplish. It is worth investing some time to look through these built-in definitions.</p> -<p>In the “search” field, type in “location”. Then, click on the “Allowed Locations” definition.</p> -<p><a href="https://lh3.googleusercontent.com/-5FJ3EcMnG8k/X7QNP-1-5II/AAAAAAAAx_A/TH4cr4SxgbQiNVdoRlDyB_F4ukOV5bJvwCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-5.png" alt=""></a></p> -<p>Here you can see the json content of the definition. The “policyRule” section is the bread and butter of the definition. In this particular example, the policyRule states that if the location that the user is deploying a resource to is NOT a) in the list of allowed locations, b) global, or c) a b2c directory, then deny the deployment.</p> -<p><a href="https://lh3.googleusercontent.com/-WKsYDX4nao4/X7QNVcSEVJI/AAAAAAAAx_E/HIbPqLSHfBIjYRRZI27X7cLjStbnXlqaQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-6.png" alt=""></a></p> -<p>Next, click on “Assign”.</p> -<p><a href="https://lh3.googleusercontent.com/-Qg35QQcnGZY/X7QNarWcMbI/AAAAAAAAx_M/Et9yP9ZNyXEU1Ow8m5BwZG8RcTBaadInQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-7.png" alt=""></a></p> -<p>You can assign the policy to a subscription or resource group. You can also create exclusions in this same window, and enable or disable the policy.</p> -<p><a href="https://lh3.googleusercontent.com/-16qmOT43oKo/X7QNfuX4KVI/AAAAAAAAx_Q/_0wak5v2CCA2yIrwLalJgvhCnBCCEJcOQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-8.png" alt=""></a></p> -<p>Click “Next”, and on the Parameters page, choose the allowed locations from the drop down menu. Then click next.</p> -<p>Azure Policy has the capability to remediate non-compliant resources. An example would be having a policy that requires anti-virus be installed on all servers. If Azure Policy detected a server that did NOT have anti-virus installed, it would use a managed identity to install AV software on the server. This particular policy does not need a remediation action, so we will just click “Next” here.</p> -<p>On the Review + Create window, review the resource and then click “Create”.</p> -<p>Back on the Azure Policy blade, select “Assignments”. We can now see that our new policy is assigned.</p> -<p><a href="https://lh3.googleusercontent.com/-K8ofsNe1ALY/X7QNrf8dfkI/AAAAAAAAx_c/3R0DRk4LKWYcGP6-LJ3vgRUcUOQaZ6r3ACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-9.png" alt=""></a></p> -<p>Back on the “Overview” page, you can track compliance for the policy. We can see here that compliance for the “Allowed Locations” policy assignment has not yet been started. This typically takes an hour or so before the compliance state is updated.</p> -<p><a href="https://lh3.googleusercontent.com/-S-zq_cWBh7Y/X7QNvjMRUrI/AAAAAAAAx_k/CG194fTLqKIHqTNMmCyJzM4W9HJ_d6aPgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-10.png" alt=""></a></p> -<p>Click on the Policy to get a more detailed view of compliance, view the definition, edit the assignment, and even create exemptions.</p> -<p><a href="https://lh3.googleusercontent.com/-9sdnYSeQZ7A/X7QNzt8EEdI/AAAAAAAAx_o/3-2_eyPVjxIFSINg8IzEhKwZzWGUgf9NQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-11.png" alt=""></a></p> - + http://localhost:1313/posts/2020-11-17-azure-policy-allowed-locations-for/ + Azure Policy allows us to control what actions users can perform regarding creating and managing resources in Azure. We can define policies for naming standards, require that certain extensions be installed on virtual machines, audit various resources for certain configurations… the possibilities are endless. In this article, well focus on defining what locations users can deploy resources in. To get started, login to the Azure Portal and search for “Policy”. - Replicate an Azure VM Image Between Regions - https://rnemeth90.github.io/posts/2020-11-03-replicate-azure-vm-image-between-regions/ + http://localhost:1313/posts/2020-11-03-replicate-azure-vm-image-between-regions/ Tue, 03 Nov 2020 20:15:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-03-replicate-azure-vm-image-between-regions/ - <p>Let’s say you have a VM in Azure North Central. You created this VM from a custom image that you maintain in an Azure image repository. Now, what if you wanted to create that same VM in Azure South Central, and use the same reference image? A standard image repository is limited to the region that it exists in. The answer here is to create a Shared Image Library, add the image to it, and then configure the image to replicate to other Azure regions.</p> -<p>This article assumes you already have an image.</p> -<p>First, create a Shared Image Gallery in Azure. Browse to the Azure portal (<a href="https://portal.azure.com/">https://portal.azure.com</a>), and (from the home page) click “create a resource”.</p> -<p><a href="https://lh3.googleusercontent.com/-LQbh5w9zFN0/X6G5qBxrC1I/AAAAAAAAx5I/QH95DqgHJzUgkC5YhWqmQ_pOXmCygVHwQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-12.png" alt=""></a></p> -<p>Search for “Shared Image Gallery” and then click “Create”.</p> -<p>Configure a subscription, resource group, and then name the Shared Image Gallery and configure what region you want it to live in. You will want to create it in the same region as your standard image repository.</p> -<p><a href="https://lh3.googleusercontent.com/-61hBPxzwPzI/X6G5w_C7-iI/AAAAAAAAx5M/GVHvFpgE2WQwupil-OSd7nZ2nJEZRI0MgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-13.png" alt=""></a></p> -<p>If you want to assign some tags to this new resource, continue to the next page. Otherwise, click “Review + Create”.</p> -<p><a href="https://lh3.googleusercontent.com/-OCPyDsSbRYo/X6G52usmBSI/AAAAAAAAx5Q/nZJuX9YZzNsWU4aJwGNkZ5kulaXb5mcGgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-14.png" alt=""></a></p> -<p>On the final page, if the validation is successful, click “Create”.</p> -<p><a href="https://lh3.googleusercontent.com/-gCwUW-ntoKA/X6G56AAogVI/AAAAAAAAx5Y/wcUUn2_P68MNl5wCWIqQTYGRqEvJMJm6QCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-15.png" alt=""></a></p> -<p>It should take less than a minute to create the shared image gallery. Once its created, click “Go to resource”.</p> -<p><a href="https://lh3.googleusercontent.com/-mZQpi2f85MQ/X6G5-7FGFUI/AAAAAAAAx5c/vPOG47n736gp87Z2rftfjvL9OcGolOGxACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-16.png" alt=""></a></p> -<p>In the shared image gallery blade, click “Add new image definition”.</p> -<p><a href="https://lh3.googleusercontent.com/-qSWGjKuUMp4/X6G6CZsRAXI/AAAAAAAAx5g/-LYCx4Qmf98k2mbjM9CC-8mKVA-zp-8rACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-17.png" alt=""></a></p> -<p>On the next page, select the region where your existing image repository lives, give the image definition a name, and then fill out the rest of the information as needed. The publisher will typically be the name of your company/organization. The offer will typically be set to the name of the overall application, being that servers typically host one piece of an application (example: database servers vs. application servers). The SKU will typically be set to the name of the component within the application (for example, a web server or database server).</p> -<p><a href="https://lh3.googleusercontent.com/-4ZaK5D-Y0FE/X6G6G3n8KsI/AAAAAAAAx5k/jd18bOcFQ1kP62-0zE1Vuhwx6WpRnEyGwCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-18.png" alt=""></a></p> -<p>Next, configure an image version. This should use the typical semantic format used in software development (major version, minor version, patch level). I will typically substitute the patch level with the date the image was captured. Probably not a best practice, but something that has served me well in the past.</p> -<p>Next, select the source image. This will be the image that you are copying from your standard image repository. You can also configure an end of life date for the image version here if you wish. In the “Target Regions” section at the bottom, select the region where you plan to create the new VM. Also select the target storage account type.</p> -<p><a href="https://lh3.googleusercontent.com/-6F59gxbQ7ws/X6G6PI4qVeI/AAAAAAAAx5w/x2SCNG8PawMUZRQS6q55kAvgsOfD8bnPACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-19.png" alt=""></a></p> -<p>You can configure some publishing options and tags on the following pages. Though, it is not required. Click “Review + create”. <span style="mso-spacerun: yes;"> </span><span style="mso-spacerun: yes;"> </span>After the validation passes, click “Create”.</p> -<p><a href="https://lh3.googleusercontent.com/-CyzD7E88UVU/X6G6TQGRu6I/AAAAAAAAx54/2yHQrYIFUp8P8JyWMuEbsfFL47UW8Il0ACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-20.png" alt=""></a></p> -<p>This process will take a few minutes to complete. Once its finished, click on “go to resource”. You now have an image that is available to be deployed in the north central region or the south central region.</p> - + http://localhost:1313/posts/2020-11-03-replicate-azure-vm-image-between-regions/ + Let’s say you have a VM in Azure North Central. You created this VM from a custom image that you maintain in an Azure image repository. Now, what if you wanted to create that same VM in Azure South Central, and use the same reference image? A standard image repository is limited to the region that it exists in. The answer here is to create a Shared Image Library, add the image to it, and then configure the image to replicate to other Azure regions. - Reset GRUB/root Password for vCenter/PSC Appliance - https://rnemeth90.github.io/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ + http://localhost:1313/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ Sat, 31 Oct 2020 01:22:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ - <p>In Redhat/Fedora/Cent, GRUB can be protected by running the grub-md5-crypt command and pasting the outputted password hash into the grub.conf file. vSphere 6.0 password protects grub by default. If you change the root password in the VAMI, the GRUB password is changed to match. If you do not change the root password, the GRUB password is “vmware”.</p> -<p>To reset the GRUB password, we need to boot into a Cent or Redhat live CD. The ISO can be obtained here: <a href="https://www.centos.org/download/">https://www.centos.org/download/</a>. Its best to upload the ISO to a datastore that the appliance has access to.</p> -<p>Stop the appliance and attach the ISO:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image.png" alt=""></p> -<p>Be sure to select the “Connect at Power On” option. Boot the VM into the ISO and select the “Troubleshooting” option.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-1.png" alt=""> -Next, choose “Rescure a Red hat (or CentOS depending on your ISO) Enterprise Linux System”</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-2.png" alt=""></p> -<p>Select “Continue” to mount the VCSA 6.0’s root filesystem in Read/write mode under /mnt/sysimage. RHEL 7.2 is capable to detect the VCSA’s root volume and mounts it.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-3.png" alt=""></p> -<p>The VCSA root filesystem is mounted under /mnt/sysimage and you can now access (and modify) it using the shell. Navigate to /mnt/sysimage/boot and list the contents. You’ll see we now have access to the grub directory:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-4.png" alt=""></p> -<p>cd to the grub directory and list the contents. Look for a file called “menu.lst”. This file holds the grub boot loader password. Open this file with vi by typing “vi menu.lst”. Navigate to the line beginning with “password” using the arrow keys, and then type “dd” to remove the line.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-5.png" alt=""> -You can then save the file by pressing “:wq” (without quotes). You can now cat the file and see that the password has been removed.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-6.png" alt=""></p> -<p>Exit the shell (this will reboot the server). Detach the ISO and boot the appliance. Once the system is booted, stop the VCSA in the GRUB menu (by pressing the escape key during boot) to break the OS root password.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-7.png"></a> -Press “e” to edit the boot commands for the kernel.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-8.png" alt=""></p> -<p>Append “init=/bin/bash” to the line in this step and press enter.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-9.png" alt=""></p> -<p>Press “b” to boot the system.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-10.png" alt=""></p> -<p>You will now boot into a bash shell where you can set the root password.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-11.png" alt=""></p> -<p>Once this is done, exit the shell by typing “exit”. You can now boot the appliance and login with your new root password.</p> - + http://localhost:1313/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ + In Redhat/Fedora/Cent, GRUB can be protected by running the grub-md5-crypt command and pasting the outputted password hash into the grub.conf file. vSphere 6.0 password protects grub by default. If you change the root password in the VAMI, the GRUB password is changed to match. If you do not change the root password, the GRUB password is “vmware”. To reset the GRUB password, we need to boot into a Cent or Redhat live CD. - Deploy a New ADDS Forest on Server 2019 Core - https://rnemeth90.github.io/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ + http://localhost:1313/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ Sat, 31 Oct 2020 01:02:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ - <p>Prerequisites:</p> -<p>Change server name and IP address -Configure time settings and NTP</p> -<p>In this post we will be reviewing the basic installation of the Active Directory Domain Services role and setup of a new forest on Windows Server Core 2019.</p> -<p>To get started, login to your server with administrator privileges. You will first need to type in “powershell” in the cmd prompt to start powershell. Once you do that, type in the following command to install the Active Directory Domain Services role:</p> -<p><a href="https://lh3.googleusercontent.com/-LnSTbXjG2Hc/X5y3R3F-eWI/AAAAAAAAx2A/lWQBpA44Dmo-Jpbck2iPmgibU6z0DM1YwCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-12.png" alt=""></a></p> -<p>After installing the role, we’ll continue by creating a new ADDS Forest and promoting this server to the primary domain controller.</p> -<p>First, we’ll need to gather a password. This password will not be used for a domain user account. The local administrator on this server will become the domain administrator account for the domain. The password we’re gathering in the next step will be used for Directory Services Restore Mode (DSRM). DSRM is a recovery mode used to recover domain controllers that won’t boot up. We technically only need a password, not a username for this account.</p> -<p>Type in the following:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$cred = Get-Credential -</span></span></code></pre></div><p>In the username field for the credentials prompt below, just type in anything you want, as the value will not be used. This prompt will store our username/password in a variable object. We can then access the password within the credential object by typing:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$cred.password -</span></span></code></pre></div><p>We can see that this password is stored as a secure string object. Let’s continue on with the Directory Services installation.</p> -<p><a href="https://lh3.googleusercontent.com/-n-W0yvwr2Zs/X5y3X64NjZI/AAAAAAAAx2E/rx5urA7p_NMl3peX5g0J7Ax7biWwNADAgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-13.png" alt=""></a></p> -<p><a href="https://lh3.googleusercontent.com/-0k-aZrMhyGw/X5y3ckH10pI/AAAAAAAAx2I/FS56uvXCirAaBHKwWmIRQ4xIGU_jp_GFwCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-14.png" alt=""></a></p> -<p>Once we have our credential variable, we can install a new forest and domain controller using the command below. Let us break down what this cmd is doing:</p> -<p><a href="https://lh3.googleusercontent.com/-OF_HVfCPZIM/X5y3ijEA5YI/AAAAAAAAx2M/0vMV3CJczT8D3q5x8hzPAZVSL5DycplBACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-15.png" alt=""></a></p> -<p>Install-ADDSForest: The powershell cmdlet to create a new forest and domain controller</p> -<p>-DomainName: The domain name to be used for the forest</p> -<p>-DomainNetBiosName: The domain “Short name” to be used for the forest. This is the value used when you type in a username in the domainusername format. Example “myDomainbgates”.</p> -<p>-SafeModeAdministratorPassword: The value we captured in our credential prompt above. This is used for Directory Services Restore Mode. This mode can be accessed by pressing F8 while the server is booting. It is commonly used for recovering a failed domain controller.</p> -<p>-DatabasePath: The path for the Active Directory database. It’s a best practice to put this database on its own disk.</p> -<p>-LogPath: The directory for ADDS log files</p> -<p>-DomainMode: The domain functional level. The domain functional level specifies the attributes and capabilities available to objects within the domain. The higher the level you choose, the more features will be available to you.</p> -<p>-ForestMode: The forest functional level. Similar to the domain functional level but applies to the entire forest.</p> -<p>-InstallDNS: Install the DNS role alongside the ADDS role.</p> -<p>-WhatIf: This is a powershell “thing”. Most cmdlets have the “whatif” parameter. It basically allows you to run the cmdlet in “test” mode without actually making any changes to your environment. Once you’re happy with the output, you can remove the “whatif” parameter and run the command to install ADDS and promote this server to a domain controller.</p> - + http://localhost:1313/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ + Prerequisites: Change server name and IP address Configure time settings and NTP In this post we will be reviewing the basic installation of the Active Directory Domain Services role and setup of a new forest on Windows Server Core 2019. To get started, login to your server with administrator privileges. You will first need to type in “powershell” in the cmd prompt to start powershell. Once you do that, type in the following command to install the Active Directory Domain Services role: - Could not connect to VMware Directory Service via LDAP when Deploying New vCenter Appliance - https://rnemeth90.github.io/posts/2020-10-28-could-not-connect-to-vmware-directory/ + http://localhost:1313/posts/2020-10-28-could-not-connect-to-vmware-directory/ Wed, 28 Oct 2020 13:51:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-28-could-not-connect-to-vmware-directory/ - <p>Problem:</p> -<p>Deploying a brand new vCSA 6.7 appliance results in the following error during the second stage of the deployment.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h29_02.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h29_02.png" alt=""></a><span style="text-align: left;"> </span></p> -<p>Solution:</p> -<p>This problem is almost always caused by DNS resolution. Once you create the appropriate A and PTR record for your appliance on a LOCAL DNS server, you should be to successfully complete the deployment. Local DNS resolution is required, you cannot use a public DNS server while installing vCenter. For example, 8.8.8.8 will not work.</p> -<p>Since you have already completed Stage 1 of the deployment, you can login to the appliance via SSH and update the DNS settings. This will only work if you chose to enable SSH during Stage 2 of the deployment.</p> -<p>SSH to the appliance and run “/opt/vmware/share/vami/vami_config_net” (without quotes). Choose option 4 to update DNS settings and option 3 to update the hostname (if necessary). The deployment wizard states that a hostname is optional, but it is actually required. I have never had a successful deployment without specifying the hostname.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h33_18.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h33_18.png" alt=""></a></p> -<p>You can then verify the DNS settings have been updated in the resolve.conf:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h33_57.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h33_57.png" alt=""></a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_08h47_36.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_08h47_36.png" alt=""></a></p> - + http://localhost:1313/posts/2020-10-28-could-not-connect-to-vmware-directory/ + Problem: Deploying a brand new vCSA 6.7 appliance results in the following error during the second stage of the deployment. Solution: This problem is almost always caused by DNS resolution. Once you create the appropriate A and PTR record for your appliance on a LOCAL DNS server, you should be to successfully complete the deployment. Local DNS resolution is required, you cannot use a public DNS server while installing vCenter. For example, 8. - Cisco AnyConnect &#8211; VPN Establishment Capability from a Remote Desktop is Disabled - https://rnemeth90.github.io/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ + http://localhost:1313/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ Wed, 07 Oct 2020 13:28:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ - <p>I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution.</p> -<p><a href="https://lh3.googleusercontent.com/-BYApW8vZjV8/X33B2Or4D7I/AAAAAAAAxuY/hWQwpE-fqo4xInAsx9vyUvzDJXqxe68QQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-16.png" alt=""></a></p> -<p>Upon installation, AnyConnect pulls down a profile from the ASA containing several settings. This profile is in xml format and is located (on a Windows machine) at %programdata%CiscoCisco AnyConnect Secure Mobility ClientProfileAnyConnectProfile.xsd.</p> -<p>To resolve this issue and connect to your VPN, open this file with notepad (or any text editor, run as admin), search for the “WindowsVPNEstablishment” tag, and modify the value. The default value is “LocalUsersOnly”, you will need to change it to “AllowRemoteUsers”. Save and close the file, then restart the machine.</p> -<p>BEFORE:</p> -<p><a href="https://lh3.googleusercontent.com/-izGUUyhtWyM/X33Bh8YdqGI/AAAAAAAAxuQ/rBbXsqWhe5wZYoGmjXwyyidGmu1kCNVmgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-17.png" alt=""></a></p> -<p>AFTER:</p> -<p><a href="https://lh3.googleusercontent.com/-wFFu1JOXymQ/X33CVp0cImI/AAAAAAAAxug/fibXC6JHmkkilFtWv8641x20flapCibYACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-18.png" alt=""></a></p> - + http://localhost:1313/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ + I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution. Upon installation, AnyConnect pulls down a profile from the ASA containing several settings. This profile is in xml format and is located (on a Windows machine) at %programdata%CiscoCisco AnyConnect Secure Mobility ClientProfileAnyConnectProfile.xsd. To resolve this issue and connect to your VPN, open this file with notepad (or any text editor, run as admin), search for the “WindowsVPNEstablishment” tag, and modify the value. - Active Directory Migration Toolkit &#8211; The RPC Server is Unavailable (hr=0x800706ba) - https://rnemeth90.github.io/posts/2018-08-21-active-directory-migration-toolkit-rpc/ + http://localhost:1313/posts/2018-08-21-active-directory-migration-toolkit-rpc/ Tue, 21 Aug 2018 17:34:00 +0000 - - https://rnemeth90.github.io/posts/2018-08-21-active-directory-migration-toolkit-rpc/ - <p>When migrating computer objects using the Active Directory Migration Tool, you may encounter the following error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_09.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_09.png" alt=""></a></p> -<p>In addition, the Migration Log may show the following error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_20.png" alt=""></a></p> -<p>This is typically caused by a host-side firewall. To resolve this, deploy a GPO to disable the Windows firewall prior to migrating the computer account. I like to create a special OU for computers (I typically name it “PreMigration”) that I will move computer objects to prior to migrating them. This OU will have two policies applied. One to disable the Windows Firewall and another to start the Remote Registry service. Both are required for the computer object to successfully migrate.</p> - + http://localhost:1313/posts/2018-08-21-active-directory-migration-toolkit-rpc/ + When migrating computer objects using the Active Directory Migration Tool, you may encounter the following error: In addition, the Migration Log may show the following error: This is typically caused by a host-side firewall. To resolve this, deploy a GPO to disable the Windows firewall prior to migrating the computer account. I like to create a special OU for computers (I typically name it “PreMigration”) that I will move computer objects to prior to migrating them. - Azure Site Recovery &#8211; VMware-to-Azure: Wrong IP address discovered for VM - https://rnemeth90.github.io/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ + http://localhost:1313/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ Tue, 21 Aug 2018 17:26:00 +0000 - - https://rnemeth90.github.io/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ - <p>When replicating virtual machines from VMware to Azure using Site Recovery, you may encounter an issue where the Configuration server discovers the wrong IP address for a VM. This can be caused by stale entries within the infrastructurevms MySQL table that is used by ASR to track VM attributes.</p> -<p>To resolve this issue, you first need to disable replication for the VM in the Azure Portal.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-21_13h20_26.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-21_13h20_26.png" alt=""></a></p> -<p>Next, login to your ASR Configuration Server and open a CMD prompt as administrator. Browse to the bin directory for your ASR installation. For example, in my case ASR is installed on the E: partition under the following directory:</p> -<p>E:\Program Files (x86)Microsoft Azure Site Recoveryhomesvsystemsbin</p> -<p>Type in this command to remove the VM from the ASR database (replace IP address with the IP of your VM):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-perl" data-lang="perl"><span style="display:flex;"><span>perl Unregister<span style="color:#f92672">-</span>ASRComponent<span style="color:#f92672">.</span>pl <span style="color:#f92672">-</span>IPAddress <span style="color:#ae81ff">10.0.0.4</span> <span style="color:#f92672">-</span>Component Source -</span></span></code></pre></div><p>That’s it. You should now be able to reconfigure replication for the VM, and ASR will discover the correct info about the VM.</p> - + http://localhost:1313/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ + When replicating virtual machines from VMware to Azure using Site Recovery, you may encounter an issue where the Configuration server discovers the wrong IP address for a VM. This can be caused by stale entries within the infrastructurevms MySQL table that is used by ASR to track VM attributes. To resolve this issue, you first need to disable replication for the VM in the Azure Portal. Next, login to your ASR Configuration Server and open a CMD prompt as administrator. - Azure AD Connect No-Start-Connection - https://rnemeth90.github.io/posts/2018-07-26-azure-ad-connect-no-start-connection/ + http://localhost:1313/posts/2018-07-26-azure-ad-connect-no-start-connection/ Thu, 26 Jul 2018 12:22:00 +0000 - - https://rnemeth90.github.io/posts/2018-07-26-azure-ad-connect-no-start-connection/ - <p>This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working.</p> -<p>After forcing the sync, I opened miisclient and noticed some strange errors. We sync multiple on-prem AD forests to Azure AD, and the status for one of them was “no-start-connection”. That error in itself does not seem significant to me. However, after clicking on the “failed-connection” link in the Connection Status pane, things became much more clear.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_05.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_05.png" alt=""></a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_18.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_18.png" alt=""></a></p> -<p>The domain controllers for the forest in question are in a datacenter that is geographically separated from the datacenter that our Azure AD Sync server lives in. The two sites are connected via a S2S VPN.</p> -<p>There was obviously some type of connection issue between our two datacenters. In my case, the issue was transient, and resolved itself after a few minutes. But if you’re experiencing this error message, check your L2/L3 connection. Also, verify DNS is working and someone didn’t make changes to your firewall(s). Just walk up or down the OSI model and you’ll eventually find the problem.</p> - + http://localhost:1313/posts/2018-07-26-azure-ad-connect-no-start-connection/ + This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working. After forcing the sync, I opened miisclient and noticed some strange errors. - Azure AD Connect Health: Latest Data is not Available in Azure Portal - https://rnemeth90.github.io/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ + http://localhost:1313/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ Wed, 18 Jul 2018 16:38:00 +0000 - - https://rnemeth90.github.io/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ - <p>I recently had to create a new Azure AD Connect server, and found that it was not able to report health status in the Azure Portal. After some troubleshooting/research, I was able to get the health status report working by registering the health agent on the server with Azure AD Health Services. Doing this involves running one PowerShell cmdlet on your AD Connect server and providing global administrator credentials.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_56.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_56.png" alt=""></a></p> -<p>First, let’s test the status of the agent communication:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_19.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_19.png" alt=""></a></p> -<p>If you do not receive any errors, that means the Azure AD Connect Health agent on your server is able to successfully communicate with the cloud service. Now, let’s register the agent:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_05.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_05.png" alt=""></a></p> -<p>You will be prompted for credentials. The credentials you provide need to be a global administrator account in your Azure AD tenant.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_42.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_42.png" alt=""></a></p> -<p>You should receive some output stating that the registration is successful (or it failed).</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h25_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h25_20.png" alt=""></a></p> -<p>Now, just go back to the Azure Portal and refresh the page. The message stating that the -“latest data is not available” should be gone.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h36_42.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h36_42.png" alt=""></a></p> - + http://localhost:1313/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ + I recently had to create a new Azure AD Connect server, and found that it was not able to report health status in the Azure Portal. After some troubleshooting/research, I was able to get the health status report working by registering the health agent on the server with Azure AD Health Services. Doing this involves running one PowerShell cmdlet on your AD Connect server and providing global administrator credentials. First, let’s test the status of the agent communication: - Removing a Forest from Azure AD Connect - https://rnemeth90.github.io/posts/2018-07-13-removing-forest-from-azure-ad-connect/ + http://localhost:1313/posts/2018-07-13-removing-forest-from-azure-ad-connect/ Fri, 13 Jul 2018 15:30:00 +0000 - - https://rnemeth90.github.io/posts/2018-07-13-removing-forest-from-azure-ad-connect/ - <p>In an organization with multiple Active Directory forests, you may want to sync objects from trusted forests. Adding trusted forests to Azure AD Sync is a simple process that I will likely cover in a future article. The focus of this post is the not-so-obvious process of removing a forest from Azure AD Connect. This can be a daunting and somewhat scary thing to do. Not fully understanding the process or having someone to guide you can leave you with thoughts like “what happens when I remove the forest from Azure AD Sync? Do on-premises objects get deleted? Are cloud objects deleted?”. I will try to answer these questions to the best of my ability and hopefully make the process simple and stress-free for you.</p> -<p>To get started, we first need to open PowerShell and disable the AD Sync scheduler. You can do this by running the “Set-ADSyncScheduler” cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h47_05.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h47_05.png" alt=""></a></p> -<p>This cmdlet is included in the ADSync PowerShell module. You may need to load the module prior to using the cmdlet:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Import-Module ADSync -</span></span></code></pre></div><p>The next step is to open FIM (miisclient) located in the install directory of Microsoft Azure AD Sync. By default, this is C:Program FilesMicrosoft Azure AD SyncUIShellmiisclient.exe. Once you have FIM open, click on the Connectors tab, then right click on the connector for the forest that you want to delete, and click “Delete”.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_26.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_26.png" alt=""></a></p> -<p>You will then be prompted, asking if you want to just delete the Connector Space, or delete the Connector and the Connector Space. The former open removes all data, but keeps the configuration in case you want to use it again later. The latter option deleted the data and the configuration. This open should only be used if you don’t plan on syncing the forest again.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_09.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_09.png" alt=""></a></p> -<p>The connector for the forest is now deleted, but what actually happens? Your on-premises objects do not get removed for the forest, and cloud objects <strong>are</strong> removed. Simple enough, right?</p> -<p>Now you just need to re-enable the AD Sync Scheduler with this cmdlet:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Set-ADSyncScheduler -SyncCycleEnabled $true -</span></span></code></pre></div><p>One last thing to mention… You may receive an email from the Microsoft Online Services Team stating that the identity synchronization failed due to a deletion threshold being met. By default, Azure AD Connect will not allow you to delete more than 500 objects in your cloud directory. This is to protect you from making a careless (potentially resume generating) mistake. The email will look something like this:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h56_04.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h56_04.png" alt=""></a></p> -<p>If you are certain that you want to proceed with deleting the objects, here are the steps:</p> -<ol> -<li> -<p>Disable the deletion threshold protection. Open PowerShell on your Azure AD Sync server and type in this cmdlet: Disable-ADSyncExportDeletionThreshold. You will be prompted for credentials, sign-in with an Azure AD Global Admin account.</p> -</li> -<li> -<p>Open FIM (miisclient), and click on the “Connectors” button at the top of the window. Right click on the connector of type “Windows Azure Active Directory”, and select “Run…”.</p> -</li> -</ol> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_39.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_39.png" alt=""></a></p> -<ol start="3"> -<li>Next, click Export and then click Ok.</li> -</ol> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_58.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_58.png" alt=""></a></p> -<ol start="4"> -<li> -<p>Allow the connector to run. This will take a few minutes. You can monitor the progress by clicking the Operations button.</p> -</li> -<li> -<p>Once this completes, you need to re-enable the deletion threshold. You can do this by running this cmdlet: <span style="background: #F9F9F9;"></p> -</li> -</ol> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Enable-ADSyncExportDeletionThreshold -DeletionThreshold <span style="color:#ae81ff">500</span>. -</span></span></code></pre></div><p>You will be prompted for credentials again. Just type in your Azure AD Global Admin creds. You can even lower the threshold if you’d like. I set mine to 100.</p> - + http://localhost:1313/posts/2018-07-13-removing-forest-from-azure-ad-connect/ + In an organization with multiple Active Directory forests, you may want to sync objects from trusted forests. Adding trusted forests to Azure AD Sync is a simple process that I will likely cover in a future article. The focus of this post is the not-so-obvious process of removing a forest from Azure AD Connect. This can be a daunting and somewhat scary thing to do. Not fully understanding the process or having someone to guide you can leave you with thoughts like “what happens when I remove the forest from Azure AD Sync? - Remove Stubborn PSC or vCenter Appliance from an SSO Domain - https://rnemeth90.github.io/posts/2017-11-08-remove-stubborn-psc-or-vcenter/ + http://localhost:1313/posts/2017-11-08-remove-stubborn-psc-or-vcenter/ Wed, 08 Nov 2017 07:56:00 +0000 - - https://rnemeth90.github.io/posts/2017-11-08-remove-stubborn-psc-or-vcenter/ - <p>While attempting to decommission one of our vCenter sites, I ran into an issue removing one of the PSCs. This site consisted of two PSCs and one vCenter appliance. I removed the first PSC from the SSO domain successfully, and then removed the vCenter appliance. Things became a little tricky during the removal of the final PSC. This PSC did not get removed even after running the cmsso-util command. This article will detail the steps I took in decommissioning the site, as well as removing the stubborn PSC.</p> -<p>First, we need to check if vCenter is currently using the PSC we plan on decommissioning. If it is, we need to use the cmsso-util command to redirect vCenter to a different PSC. Instructions for redirecting vCenter can be found here: <a href="https://kb.vmware.com/s/article/2113917?language=en_US">https://kb.vmware.com/s/article/2113917?language=en_US</a></p> -<p>To check what PSC your vCSA is currently pointing to, browse to the Advanced Settings for the vCSA in the vSphere Web Client. Filter by this key: config.vpxd.sso.admin.uri</p> -<p>To remove a PSC or vCSA from an SSO domain, connect to a PSC via SSH and run these commands:</p> -<p>To remove a PSC from the vSphere SSO domain:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>cmsso-util unregister –node-pnid psc01.ad.vcplab.local –username administrator@your<span style="color:#ae81ff">\_</span>domain<span style="color:#ae81ff">\_</span>name –passwd vCenter<span style="color:#ae81ff">\_</span>Single<span style="color:#ae81ff">\_</span>Sign<span style="color:#ae81ff">\_</span>On<span style="color:#ae81ff">\_</span>password -</span></span></code></pre></div><p>To remove a vCSA from the vSphere SSO domain:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>cmsso-util unregister –node-pnid vcsa.ad.vcplab.local –username administrator@your<span style="color:#ae81ff">\_</span>domain<span style="color:#ae81ff">\_</span>name –passwd vCenter<span style="color:#ae81ff">\_</span>Single<span style="color:#ae81ff">\_</span>Sign<span style="color:#ae81ff">\_</span>On<span style="color:#ae81ff">\_</span>password -</span></span></code></pre></div><p>After running these commands, delete the virtual appliances. You can also verify the appliances have been removed by browsing to Administration &gt; System Configuration &gt; Nodes in the vSphere Web Client.</p> -<p>If cmsso-util fails to remove any of the nodes, you can use this command to force the removal:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>vdcleavefed -h vcsa.ad.vcplab.local -u Administrator -w Passw0rd! -</span></span></code></pre></div><p>Upon successful completion, you should see something like this:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>/usr/lib/vmware-vmdir/bin/vdcleavefed -h vcsa.ad.vcplab.local -u administrator* password: -</span></span><span style="display:flex;"><span>vdcleavefd offline <span style="color:#66d9ef">for</span> server vcsa.ad.vcplab.local -</span></span><span style="display:flex;"><span>Leave federation cleanup <span style="color:#66d9ef">done</span> -</span></span></code></pre></div><p>When specifying the username, use the SSO admin (administrator). However, do not use the full UPN (<a href="mailto:administrator@vsphere.local">administrator@vsphere.local</a>). Doing so will cause the command to fail.</p> - + http://localhost:1313/posts/2017-11-08-remove-stubborn-psc-or-vcenter/ + While attempting to decommission one of our vCenter sites, I ran into an issue removing one of the PSCs. This site consisted of two PSCs and one vCenter appliance. I removed the first PSC from the SSO domain successfully, and then removed the vCenter appliance. Things became a little tricky during the removal of the final PSC. This PSC did not get removed even after running the cmsso-util command. This article will detail the steps I took in decommissioning the site, as well as removing the stubborn PSC. - Exchange 2016 Hybrid Deploy Check: Username or Password Invalid - https://rnemeth90.github.io/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ + http://localhost:1313/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ Tue, 07 Nov 2017 13:30:00 +0000 - - https://rnemeth90.github.io/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ - <p>These days, it seems every Microsoft product comes with its own unique set of head scratchers. Microsoft Exchange Server is no exception to this. I was installing Exchange 2016 earlier today, to be used as a hybrid configuration server for Office 365 (no local mailboxes). I downloaded the self depackaging executable from Microsoft, and attempted to install it. If you currently have a hybrid configuration (which we did, with Exchange 2010), the Exchange 2016 installer will detect this and run some tests to verify that the Office 365 tenant is ready for Exchange 2016 (more info here: <a href="https://technet.microsoft.com/en-us/library/ms.exch.setup.hybridconfigurationstatuspage(v=exchg.160).aspx">https://technet.microsoft.com/en-us/library/ms.exch.setup.hybridconfigurationstatuspage(v=exchg.160).aspx</a>). You’ll be prompted for Office 365 credentials (the user must have the Organization Management role). Seems simple enough, right? Wrong.</p> -<p>After typing in the username and <em>pasting</em> the password into the password field, setup came back with an error message stating the username or password was wrong. I then clicked the back button, and it crashed. I ran through this process a few more times, all with the same outcome. I even rebooted the server, which (in my opinion) should never be the resolution to a software problem. I looked through setup logs and found no indication of what the problem could be…</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2017/11/2017-11-07_12h57_08.png" alt=""></p> -<p>It was on the fourth try that I typed in the password, and this seemed to work. I didn’t receive any error messages about the credentials being wrong. The Exchange setup seemed to continue on successfully. However, it then failed with a different error:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2017/11/2017-11-07_13h12_02.png" alt=""></p> -<p>I again looked through the setup logs and found that this error happened anytime setup tried to run the “Get-OrganizationConfig” cmdlet. After troubleshooting for a little while, and no resolution in sight, I turned to Google. One of the posts I came across said that this is a bug in the Exchange installer, and to try and use the Cumulative Update installer instead. Apparently, with Exchange 2016, the Cumulative Update installer’s include all of the Exchange binaries, not just the updated binaries. I downloaded the installer for CU7 (all 6 gigabytes of it…) and successfully installed Exchange 2016. Hope this helps anyone out there struggling with this.</p> - + http://localhost:1313/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ + These days, it seems every Microsoft product comes with its own unique set of head scratchers. Microsoft Exchange Server is no exception to this. I was installing Exchange 2016 earlier today, to be used as a hybrid configuration server for Office 365 (no local mailboxes). I downloaded the self depackaging executable from Microsoft, and attempted to install it. If you currently have a hybrid configuration (which we did, with Exchange 2010), the Exchange 2016 installer will detect this and run some tests to verify that the Office 365 tenant is ready for Exchange 2016 (more info here: https://technet. - Migrate Windows Deployment Services to New Server - https://rnemeth90.github.io/posts/2017-06-27-migrate-windows-deployment-services-to-new-server/ + http://localhost:1313/posts/2017-06-27-migrate-windows-deployment-services-to-new-server/ Tue, 27 Jun 2017 09:21:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-27-migrate-windows-deployment-services-to-new-server/ - <p>We have been making a great effort to move all of our internal services to Windows Server 2016. This past week, it was WDS’ turn to get migrated. Migrating this role is extremely simple. Here are the steps that I took:</p> -<ol> -<li>Create new server and install WDS role.</li> -<li>Stop WDS Service on old server</li> -<li>Stop WDS Service on new server</li> -<li>Use my “Copy-Files” PowerShell script (Available Here: <a href="https://gallery.technet.microsoft.com/scriptcenter/Copy-Files-17cba2ae">Copy-Files.ps1</a>) to copy RemoteInstall Share to new server</li> -<li>Start WDS Service on new Server</li> -<li>Shutdown old WDS Server completely</li> -<li>Update option 66/67 in DHCP scopes to reflect new WDS Server</li> -<li>Update any appropriate DNS records</li> -</ol> -<p>Note:</p> -<p>If you are unable to start the WDS service, delete the WDS database and logs from the old server located at &lt;drive letter&gt;:RemoteInstallStoresMetadata*.*. You should be able to start the service after deleting these files.</p> -<p>Simple enough! 🙂</p> - + http://localhost:1313/posts/2017-06-27-migrate-windows-deployment-services-to-new-server/ + We have been making a great effort to move all of our internal services to Windows Server 2016. This past week, it was WDS’ turn to get migrated. Migrating this role is extremely simple. Here are the steps that I took: Create new server and install WDS role. Stop WDS Service on old server Stop WDS Service on new server Use my “Copy-Files” PowerShell script (Available Here: Copy-Files.ps1) to copy RemoteInstall Share to new server Start WDS Service on new Server Shutdown old WDS Server completely Update option 66/67 in DHCP scopes to reflect new WDS Server Update any appropriate DNS records Note: - New Script: BulkAdd-SpamFilterWhitelist.ps1 - https://rnemeth90.github.io/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ + http://localhost:1313/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ Mon, 26 Jun 2017 22:16:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ - <p>This script is capable of adding a list of domains to an Exchange Online Spam Filter policy. It can be downloaded from TechNet or Github.</p> -<p><a href="https://github.com/rnemeth90/PowerShell/blob/master/BulkAdd-SpamFilterWhitelist.ps1">Github</a></p> -<p><a href="https://gallery.technet.microsoft.com/BulkAdd-SpamFilterWhitelist-2d2b596a">TechNet</a></p> - + http://localhost:1313/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ + This script is capable of adding a list of domains to an Exchange Online Spam Filter policy. It can be downloaded from TechNet or Github. Github TechNet - Windows 8 File History - https://rnemeth90.github.io/posts/2017-06-22-windows-8-file-history-windows-8-file-history/ + http://localhost:1313/posts/2017-06-22-windows-8-file-history-windows-8-file-history/ Thu, 22 Jun 2017 22:42:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-22-windows-8-file-history-windows-8-file-history/ - <p>File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. To begin using it, connect an external drive and search for File History on the Start Screen:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2014-11-15_14h19_47.png" alt=""></p> -<p>After opening File History, you will see this screen:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2014-11-15_14h20_32.png" alt=""></p> -<p>To enable File History, click the ‘Turn On’ button. You can select the drive you want to use by clicking ‘Select Drive’ on the left hand side from this same screen. The first time you enable File History, it will create a full backup of all files on your computer, except for files that you do not access (system files), and files you have chosen to exclude. From then on, it will create a versioned copy of every file that has changed since the last backup.</p> -<p>You can use a locally attached drive or a network share for File History. To choose how often File History backs up files; choose ‘Advanced Settings’. From here you can also choose how much space on the drive is used, and how long saved versions of files should be kept.</p> -<p>When the total space allocated to File History has been used, the feature will delete the oldest versions of files to make room for newer versions.</p> - + http://localhost:1313/posts/2017-06-22-windows-8-file-history-windows-8-file-history/ + File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. - How to Permanently Remove Office 365 Users - https://rnemeth90.github.io/posts/2017-06-20-how-to-permanently-remove-office-365-users/ + http://localhost:1313/posts/2017-06-20-how-to-permanently-remove-office-365-users/ Tue, 20 Jun 2017 18:13:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-20-how-to-permanently-remove-office-365-users/ - <p>After deleting a user in Office 365, their account is moved to a ‘recycle bin’ for 30 days. This allows the user account to be easily recovered. This can often cause issues when attempting to recreate a mailbox while a hybrid configuration is in place.</p> -<p>To permanently delete the user within Office 365, first delete the user in the Office 365 Admin Portal or using Powershell. Then, connect to your Azure Active Directory environment with Powershell using the “Connect-MsolService” cmdlet.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h06_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h06_20.png" alt=""></a></p> -<p>To see a list of user accounts currently in the recycle bin, run this cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h09_47.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h09_47.png" alt=""></a></p> -<p>Then, to permanently delete all accounts in the recycle bin, run this cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h10_16.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h10_16.png" alt=""></a></p> -<p>To remove a specific user, run this cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h11_15.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h11_15.png" alt=""></a></p> - + http://localhost:1313/posts/2017-06-20-how-to-permanently-remove-office-365-users/ + After deleting a user in Office 365, their account is moved to a ‘recycle bin’ for 30 days. This allows the user account to be easily recovered. This can often cause issues when attempting to recreate a mailbox while a hybrid configuration is in place. To permanently delete the user within Office 365, first delete the user in the Office 365 Admin Portal or using Powershell. Then, connect to your Azure Active Directory environment with Powershell using the “Connect-MsolService” cmdlet. - Access is Denied When Attempting to Delete a Dynamic Distribution Group - https://rnemeth90.github.io/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ + http://localhost:1313/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ Mon, 12 Jun 2017 13:41:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ - <p>You may receive the error below when attempting to delete a dynamic distribution group.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-12_09h29_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-12_09h29_20.png" alt=""></a></p> -<p>To resolve this, open ADUC and show advanced features (Click View &gt; Advanced Features). Then find the object for the dynamic distribution group and open the properties window. Browse to the “Object” tab and uncheck the “Protect object from accidental deletion” box. Wait for ADDS to replicate or force replication yourself.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-12_09h34_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-12_09h34_20.png" alt=""></a></p> -<p>Go back to the ECP and you should be able to delete the group.</p> - + http://localhost:1313/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ + You may receive the error below when attempting to delete a dynamic distribution group. To resolve this, open ADUC and show advanced features (Click View &gt; Advanced Features). Then find the object for the dynamic distribution group and open the properties window. Browse to the “Object” tab and uncheck the “Protect object from accidental deletion” box. Wait for ADDS to replicate or force replication yourself. Go back to the ECP and you should be able to delete the group. - Running vSphere in VMware Workstation 12 - https://rnemeth90.github.io/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/ + http://localhost:1313/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/ Mon, 29 May 2017 01:09:00 +0000 - - https://rnemeth90.github.io/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/ - <p>In this post I’ll be walking through how to run a vSphere lab in VMware Workstation. I recently decided to obtain VCP6-DCV. Rather than driving up my electric bill like I’ve done in the past using physical servers, I’m attempting to run the entire lab on my workstation and a Synology NAS.</p> -<p>If you’ve ever installed ESXi, installing it in Workstation will be a familiar process for you. VMware tools is included in the installation disc, which makes installing ESXi in Workstation dramatically easier than it used to be. . The process is very simple, so I won’t be going through those steps here unless someone asks me to in the comments. I also will not be going through the process of installing Windows Server or configuring a domain controller/DNS/DHCP, as I am sure you have done so in the past if you are reading this.</p> -<p>So that really only leaves us with installing vCenter. Most of the blogs I found for installing vCenter in VMware Workstation 12 were not accurate, and often left me with a broken installation. The process is somewhat straight-forward when deploying from the OVA. Let’s get started.</p> -<p>First, download the OVA for vCenter here: <a href="https://my.vmware.com/web/vmware/details?productId=614&amp;downloadGroup=VC650">Download vCenter</a></p> -<p>Once the download has completed, click File &gt; Open in Workstation. Browse to the OVA, then give your new VM a name and location if necessary. Accept the EULA when prompted.</p> -<p>Be sure to read it! 😎</p> -<p>Once the OVA finishes importing, do not power on the VM! There is some customization we need to do first. Close Workstation if it is open. Browse to the location on your PC that you imported the VM to. I’m using a Windows OS, so I will use File Explorer. Open the .VMX file (use Notepad or another text editor):</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-28_21h00_04.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-28_21h00_04.png" alt=""></a></p> -<p>This is the configuration file for your virtual machine. We can use it to customize the name, IPv4/6 details, DNS domain, etc. Scroll down to the last line of text, and paste this in:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>guestinfo.cis.vmdir.password <span style="color:#f92672">=</span> “vmware!” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.addr.family <span style="color:#f92672">=</span> “ipv4” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.addr <span style="color:#f92672">=</span> “10.0.0.15” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.prefix <span style="color:#f92672">=</span> “24” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.mode <span style="color:#f92672">=</span> “static” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.dns.servers <span style="color:#f92672">=</span> “10.0.0.10” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.gateway <span style="color:#f92672">=</span> “10.0.0.1” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.root.passwd <span style="color:#f92672">=</span> “vmware!” -</span></span></code></pre></div><p>Customize the above code to your needs. You will likely need to change the IPv4 details. Save the .VMX file and close your text editor. Now you can power on the virtual machine, and vCenter will run through the installation process. The installation can take around 10-15 minute in my experience. You may see generic login screens during the installation of Photon, do not login or interrupt the installation. Once it is complete, you should see the DCUI below:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h11_00.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h11_00.png" alt=""></a></p> -<p>You should now be able to browse to the IP address or DNS name of your vCenter server. Once you complete the configuration, you can login and see the page below: -<a href="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h10_39.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h10_39.png" alt=""></a></p> -<p>In my lab I am running 3 ESXi hosts, 1 Windows Server, and one vCenter server. Plenty to study for the VCP lab.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h11_31.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h11_31.png" alt=""></a></p> -<p>Good luck and be sure to leave a comment if you have any questions!</p> - + http://localhost:1313/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/ + In this post I’ll be walking through how to run a vSphere lab in VMware Workstation. I recently decided to obtain VCP6-DCV. Rather than driving up my electric bill like I’ve done in the past using physical servers, I’m attempting to run the entire lab on my workstation and a Synology NAS. If you’ve ever installed ESXi, installing it in Workstation will be a familiar process for you. VMware tools is included in the installation disc, which makes installing ESXi in Workstation dramatically easier than it used to be. - WSUS: Update Files Not Downloading (Content File Download Failed) - https://rnemeth90.github.io/posts/2016-11-18-wsus-update-files-not-downloading/ + http://localhost:1313/posts/2016-11-18-wsus-update-files-not-downloading/ Fri, 18 Nov 2016 15:13:00 +0000 - - https://rnemeth90.github.io/posts/2016-11-18-wsus-update-files-not-downloading/ - <p>This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-18_10h02_21.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-18_10h02_21.png" alt=""></a></p> -<p>You may also see this event (or similar) in the Event Log.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_32.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_32.png" alt=""></a></p> -<p>This problem is caused by not specifying a valid path when assigning the WSUS content drive when first installing the role. The first time you load the WSUS console after installing the role, you will be prompted to specify the path to store Windows Update files. WSUS does not like to have its content directory be the root of a partition. For example, if I were to specify “e:” as the path for the Windows Update content, the wizard would give you an error message stating that the path is not valid. However, it doesn’t prompt you to re-enter the path if you click close. The WSUS console opens immediately after and that invalid path is where WSUS will try to store your update files. This is and has been a known bug for a while and needs to be addressed by Microsoft. Evidence of the invalid path can be found in the registry under:</p> -<p>HKLMSoftwareMicrosoftUpdate ServicesServerSetupContentDir</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_44.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_44.png" alt=""></a></p> -<p>If you come across this problem, you can change the ContentDir above to a valid path. Keep in mind that it cannot be the root of a partition. You need to specify a drive letter with a subfolder (eg: e:wsus).</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h54_54.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h54_54.png" alt=""></a></p> -<p>The other option is to reinstall the WSUS role. If you remove the role, the WID database is not removed, unless you remove that role as well (or manually delete the database). This means that when you reinstall the WSUS role, it will be able to use that same database and any clients that have contacted the WSUS server will immediately show up in the console. The same is true for update metadata. The new WSUS installation will still have the same approvals, denials, etc. as the old installation.</p> -<p>Regardless of what option you choose, I suggest rebooting the server after you make the changes.</p> - + http://localhost:1313/posts/2016-11-18-wsus-update-files-not-downloading/ + This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates: You may also see this event (or similar) in the Event Log. This problem is caused by not specifying a valid path when assigning the WSUS content drive when first installing the role. The first time you load the WSUS console after installing the role, you will be prompted to specify the path to store Windows Update files. - WSUS: An error occurred trying to connect the WSUS server - https://rnemeth90.github.io/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ + http://localhost:1313/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ Thu, 10 Nov 2016 15:18:00 +0000 - - https://rnemeth90.github.io/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ - <p>Ran into this error message when configuring a new WSUS server:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h56_00.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h56_00.png" alt=""></a></p> -<p>Restarted the WSUS, WID, and IIS services to no avail. I even rebooted the server. The WSUS console would work for a short period of time, and then would randomly stop working.</p> -<p>I found that the WSUS app pool in IIS was being disabled anytime new clients connected to the server. I believe this was because the app pool was running out of usable memory.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h28_56.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h28_56.png" alt=""></a></p> -<p>You can manually start the app pool in IIS, but it will continue to crash.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h56_48.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h56_48.png" alt=""></a></p> -<p>The solution for me was to increase the memory limit available for the application pool:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h57_38.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h57_38.png" alt=""></a></p> -<p>By default it is only configured to use just under 2 GBs. I reconfigured it to use up to 4 GB and the WSUS console has not crashed since. After re-configuring the memory for the application pool, run an IIS reset or reboot the server.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h31_40.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h31_40.png" alt=""></a></p> -<p>UPDATE: Setting the Private Memory Limit to “0” will allow the application pool to use whatever amount of memory it needs.</p> - + http://localhost:1313/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ + Ran into this error message when configuring a new WSUS server: Restarted the WSUS, WID, and IIS services to no avail. I even rebooted the server. The WSUS console would work for a short period of time, and then would randomly stop working. I found that the WSUS app pool in IIS was being disabled anytime new clients connected to the server. I believe this was because the app pool was running out of usable memory. - WDS Service: The Service did not respond in a timely fashion - https://rnemeth90.github.io/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ + http://localhost:1313/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ Thu, 10 Nov 2016 02:19:00 +0000 - - https://rnemeth90.github.io/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ - <p>This was a new one for me. Usually WDS is rock solid and it just works.</p> -<p>Anyway, I was getting ready to deploy some servers in my lab and found that I couldn’t get WDS to start on my deployment server. I got this error message when trying to start the service:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h02_29.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h02_29.png" alt=""></a></p> -<p>I then tried to start the service from the Services console and got this error message:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h02_42.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h02_42.png" alt=""></a></p> -<p>“This was just working yesterday”, I said to myself. What could possibly have happened since yesterday evening that could cause this? I looked in the event log and after scrolling through the Administrative Events, I found this:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h04_33.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h04_33.png" alt=""></a></p> -<p>The solution was so obvious it was staring me in the face, but I wanted to verify first. So I fired up a cmd prompt and ran netstat, and found this:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h06_14.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h06_14.png" alt=""></a></p> -<p>I had installed DHCP on this server the night before and totally forgot about it. Anyway, the solution was simple. I just needed to tell the WDS service to not listen on port 67. To do that, just open the WDS server properties and got to the “DHCP” tab. Then check the box next to “Do not listen on DHCP Ports”.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h08_04.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h08_04.png" alt=""></a></p> -<p>I was then able to start the DHCP service.</p> - + http://localhost:1313/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ + This was a new one for me. Usually WDS is rock solid and it just works. Anyway, I was getting ready to deploy some servers in my lab and found that I couldn’t get WDS to start on my deployment server. I got this error message when trying to start the service: I then tried to start the service from the Services console and got this error message: “This was just working yesterday”, I said to myself. - Script to Move All Disabled AD Objects to a Specified OU - https://rnemeth90.github.io/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ + http://localhost:1313/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ Thu, 06 Oct 2016 03:03:00 +0000 - - https://rnemeth90.github.io/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ - <p>The title says it all. This script will move all disabled AD objects to a specified OU. This script accepts parameters that will allow you to specify whether you want to move Users or Computers and the destination OU. It also accepts a “test mode” parameter that will run the script and output the results, without actually modifying Active Directory.</p> -<p>This is revision 1 of the script. There are still several improvements I would like to make, including better error handling and recovery.</p> -<p>If you have any suggestions or requests, please leave a comment.</p> -<p><a href="https://drive.google.com/open?id=0B2K6VOnt6zeXMVFleWZISHZBTnc">Download Here</a></p> - + http://localhost:1313/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ + The title says it all. This script will move all disabled AD objects to a specified OU. This script accepts parameters that will allow you to specify whether you want to move Users or Computers and the destination OU. It also accepts a “test mode” parameter that will run the script and output the results, without actually modifying Active Directory. This is revision 1 of the script. There are still several improvements I would like to make, including better error handling and recovery. - Script for Setting the License for Multiple Office 365 User Accounts - https://rnemeth90.github.io/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ + http://localhost:1313/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ Mon, 11 Apr 2016 01:25:00 +0000 - - https://rnemeth90.github.io/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ - <p>A script for setting the Office 365 license for multiple users. Requires a CSV file named users.csv. This file must in the same directory as the script. The CSV file must contain three columns. The title of the columns should be UPN, UsageLocation, and SKU.</p> -<p><a href="https://drive.google.com/open?id=0B2K6VOnt6zeXZ2Z6OFZhZVoyenc">BulkSet-MsolUserLicense.ps1</a></p> - + http://localhost:1313/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ + A script for setting the Office 365 license for multiple users. Requires a CSV file named users.csv. This file must in the same directory as the script. The CSV file must contain three columns. The title of the columns should be UPN, UsageLocation, and SKU. BulkSet-MsolUserLicense.ps1 - The User Profile Service service failed the logon - https://rnemeth90.github.io/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ + http://localhost:1313/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ Wed, 30 Dec 2015 10:38:00 +0000 - - https://rnemeth90.github.io/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ - <p>One of my clients had a really strange issue the other day. He has a domain admin account in his domain and was not able to login to a server that I recently built. The server was an Exchange 2013 box, and was used in Coexistence mode to migrate his company from an Exchange 2007 box.</p> -<p>He was getting this error message when attempting to login:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/12/2015-12-30_09h38_53.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/12/2015-12-30_09h38_53.png" alt=""></a></p> -<p>This is a classic error message that I’m sure most technicians have seen before. Usually the resolution is to go into the registry and rename the user profile key to have a “.bak” extension and then do some other magic. However, this time, that was not the case. I looked in the registry and didn’t even see a reg key for his profile. I then looked in the c:users folder and didn’t see a folder for his profile. Strange…</p> -<p>So what exactly was happening? Well, I took a look at the Event Viewer and found this error message:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/12/2015-12-30_09h34_06.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/12/2015-12-30_09h34_06.png" alt=""></a></p> -<p>I browsed to the file referenced in the error message and deleted it. Walla! He was able to login with his admin account. I’m not sure why this file was in the default user profile. It has something to do with Customer Experience Improvement Program:</p> -<p><a href="http://www.nextofwindows.com/what-is-sqmdata-and-sqm-file-in-windows-7-and-how-to-delete-them">http://www.nextofwindows.com/what-is-sqmdata-and-sqm-file-in-windows-7-and-how-to-delete-them</a></p> - + http://localhost:1313/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ + One of my clients had a really strange issue the other day. He has a domain admin account in his domain and was not able to login to a server that I recently built. The server was an Exchange 2013 box, and was used in Coexistence mode to migrate his company from an Exchange 2007 box. He was getting this error message when attempting to login: This is a classic error message that I’m sure most technicians have seen before. - Azure AD Connect Password Sync &#8211; Disabled and Grayed Out - https://rnemeth90.github.io/posts/2015-10-15-azure-ad-connect-password-sync-disabled/ + http://localhost:1313/posts/2015-10-15-azure-ad-connect-password-sync-disabled/ Thu, 15 Oct 2015 10:18:00 +0000 - - https://rnemeth90.github.io/posts/2015-10-15-azure-ad-connect-password-sync-disabled/ - <p>Ran into a problem earlier with the new Azure AD Connect Wizard. We had configured the wizard and synced around 500 AD accounts. However, password sync was not working. I opened the wizard to confirm the configuration and found that “Password Hash Synchronization” was disabled. It was greyed out and could not be enabled.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_08h43_18.jpg"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_08h43_18.jpg" alt=""></a></p> -<p>I called Microsoft and worked for a couple hours with a technician to resolve the issue. Thought I should post the resolution here in case anyone else encounters this.</p> -<p>You can enable password sync by running the following script:</p> -<p>Import-Module ADSync</p> -<p>$adConnector = “&lt;Local AD Connector Name&gt;”</p> -<p>$aadConnector = “&lt;Azure AD Connector Name&gt;”</p> -<p>Set-ADSyncAADPasswordSyncState -ConnectorName $aadConnector –Enable $true</p> -<p>Set-ADSyncAADPasswordSyncConfiguration -SourceConnector $adConnector -TargetConnector $aadConnector -Enable $true</p> -<p>get-ADSyncAADPasswordSyncConfiguration -sourceconnector $adConnector</p> -<p>You need to set the value of the $adConnector and $aadConnector variables with the names of your Connectors found in the MIISClient.</p> -<p>Open the MIISClient by browsing to:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_09h39_42.jpg"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_09h39_42.jpg" alt=""></a></p> -<p>Right click on MIISClient.exe and click “Run As Administrator”.</p> -<p>You can obtain the names of your connectors in by going to the Connectors tab and looking at the Names column. There are two values here that you need to pay attention to. The Windows Azure Active Directory connector is your Azure Connector (obviously), and the other connector is your on-prem connector.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_09h39_31.jpg"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_09h39_31.jpg" alt=""></a></p> -<p>Now that you have the names, just plug them into the script and run it. You can go back to the Azure AD Connect Wizard and verify that password sync is enabled. You can also go to the Event Viewer -&gt; Application log and look for events 576 and 577. These two events are related to password sync and should show you all AD accounts that have successfully synced passwords.</p> -<p>You can force a sync by going to this location and running “DirectorySyncClientCmd.exe”.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_10h21_12.jpg"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_10h21_12.jpg" alt=""></a></p> - + http://localhost:1313/posts/2015-10-15-azure-ad-connect-password-sync-disabled/ + Ran into a problem earlier with the new Azure AD Connect Wizard. We had configured the wizard and synced around 500 AD accounts. However, password sync was not working. I opened the wizard to confirm the configuration and found that “Password Hash Synchronization” was disabled. It was greyed out and could not be enabled. I called Microsoft and worked for a couple hours with a technician to resolve the issue. Thought I should post the resolution here in case anyone else encounters this. - Finding All Mailboxes with a Forwarding Address in Exchange 2003 - https://rnemeth90.github.io/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ + http://localhost:1313/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ Mon, 07 Sep 2015 23:13:00 +0000 - - https://rnemeth90.github.io/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ - <p>Believe it or not, the MSP I work for still has a client who is using Exchange 2003 as their primary email service. Despite several attempts at convincing them of the power of Office 365, they refuse to migrate. Last week the CFO contacted me and requested we provide them with a report of all users who have their email forwarded to another mailbox. “Ok, no problem.” I said helpfully as the client informed me of their request (at the time I didn’t even think about them having Exchange 2003…). I figured I would just connect to their server and do some quick PowerShell magic, and that would be it. Quick and painless, right? Wrong.</p> -<p>I did the RDP dance and got connected to their server, and my jaw just about hit the floor when I couldn’t find the Exchange Management Shell! I asked around the office to see if any of the other guys could help, but no one knew what to do. However, after talking with one of the guys, I remembered that this is Active Directory we are dealing with. There are objects, and those objects have attributes. The mailboxes/user accounts are objects, and those objects have attributes. So what attribute is it that controls forwarding addresses? I manually found one of the users who had a forwarding address configured. Then I opened up Active Directory Users and Computers, opened up her account properties, and went to the Attribute Editor tab. I filtered for attributes that have values and was able to see the email address that her mail was forwarding to. This was the “altRecipient” attribute.</p> -<p>I then did an “Advanced” search in Active Directory Users and Computers for any objects that have the “altRecipient” attribute configured, like so:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/09/ExchangeForwarding.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/09/ExchangeForwarding.png" alt=""></a></p> -<p>This search showed me all of the mailboxes that have an alternate recipient (forwarding address) configured. Not sure if there is another way to obtain this information, but this is the way that worked for me. Hopefully this article is able to help someone in the same situation.</p> - + http://localhost:1313/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ + Believe it or not, the MSP I work for still has a client who is using Exchange 2003 as their primary email service. Despite several attempts at convincing them of the power of Office 365, they refuse to migrate. Last week the CFO contacted me and requested we provide them with a report of all users who have their email forwarded to another mailbox. “Ok, no problem.” I said helpfully as the client informed me of their request (at the time I didn’t even think about them having Exchange 2003…). - Script for Querying All AD Computers Time Source - https://rnemeth90.github.io/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ + http://localhost:1313/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ Tue, 01 Sep 2015 21:05:00 +0000 - - https://rnemeth90.github.io/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ - <p>This script will iterate through all computers in Active Directory and return the configured time server for each computer.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span><span style="color:#75715e">&lt;# -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">SYNOPSIS</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Get time source for all computers in domain -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">EXAMPLE</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Get-TimeSource -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">NOTES</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Author: Ryan Nemeth - RyanNemeth@live.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Site: http://www.geekyryan.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">LINK</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> http://www.geekyryan.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">DESCRIPTION</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> This function will iterate through all computers/servers in a domain and return the time source -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> for each. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#&gt;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Write-Host -foregroundcolor Red -BackgroundColor black <span style="color:#e6db74">&#34;This script must be run on a domain controller and requires that the AD Powershell module be installed&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$module = Get-Module -ListAvailable | Select-Object -ExpandProperty Name -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span>($module <span style="color:#f92672">-notcontains</span> <span style="color:#e6db74">&#34;ActiveDirectory&#34;</span>) { -</span></span><span style="display:flex;"><span> Write-Host -foregroundcolor red -backgroundcolor black <span style="color:#e6db74">&#34;***Active Directory Powershell Module Not Found***&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span> { -</span></span><span style="display:flex;"><span> Write-Host -foregroundcolor yellow <span style="color:#e6db74">&#34;Found Active Directory Powershell Module. Importing...&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Import-Module ActiveDirectory -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$computers = get-adcomputer -filter * | Select-Object -ExpandProperty Name -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span>($computer <span style="color:#66d9ef">in</span> $computers) { -</span></span><span style="display:flex;"><span> $tm_source = w32tm /query /computer<span style="color:#960050;background-color:#1e0010">:</span>$computer /source -</span></span><span style="display:flex;"><span> write-host <span style="color:#e6db74">&#34;The time source for&#34;</span> $computer <span style="color:#e6db74">&#34;is&#34;</span> $tm_source -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><img src="https://github.com/rnemeth90/PowerShell/blob/master/NTP/Get-TimeSource.ps1" alt=""></p> - + http://localhost:1313/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ + This script will iterate through all computers in Active Directory and return the configured time server for each computer. &lt;# .SYNOPSIS Get time source for all computers in domain .EXAMPLE Get-TimeSource .NOTES Author: Ryan Nemeth - RyanNemeth@live.com Site: http://www.geekyryan.com .LINK http://www.geekyryan.com .DESCRIPTION This function will iterate through all computers/servers in a domain and return the time source for each. #&gt; Write-Host -foregroundcolor Red -BackgroundColor black &#34;This script must be run on a domain controller and requires that the AD Powershell module be installed&#34; $module = Get-Module -ListAvailable | Select-Object -ExpandProperty Name if($module -notcontains &#34;ActiveDirectory&#34;) { Write-Host -foregroundcolor red -backgroundcolor black &#34;***Active Directory Powershell Module Not Found***&#34; } else { Write-Host -foregroundcolor yellow &#34;Found Active Directory Powershell Module. - Error When Reinstalling DirSync - https://rnemeth90.github.io/posts/2015-08-13-error-when-reinstalling-dirsync/ + http://localhost:1313/posts/2015-08-13-error-when-reinstalling-dirsync/ Thu, 13 Aug 2015 18:59:00 +0000 - - https://rnemeth90.github.io/posts/2015-08-13-error-when-reinstalling-dirsync/ - <p>Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process:</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2015/08/1.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/1.png" alt=""></a></p> -<p>I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do:</p> -<ul> -<li>Uninstall Windows Azure Active Directory Sync tool and reboot -<a href="https://geekyryan.com/wp-content/uploads/2015/08/2.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/2.png" alt=""></a></li> -</ul> -<p>Remove this directory and all subfolders: C:Program FilesWindows Azure Active Directory Sync -<a href="https://geekyryan.com/wp-content/uploads/2015/08/3.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/3.png" alt=""></a></p> -<p>If you created a domain account to use for DirSync, remove it. Also remove the Office 365 account you created.</p> -<ul> -<li>Delete the Group accounts that the DirSync wizard created. Their names all begin with “FIM”</li> -</ul> -<p><a href="https://geekyryan.com/wp-content/uploads/2015/08/4.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/4.png" alt=""></a></p> -<p>Uninstall MSSQL:</p> -<ul> -<li>Delete the MSSQL directory: C:Program FilesMicrosoft SQL Server</li> -<li>Reboot!</li> -<li>You should be able to install and configure DirSync now.</li> -</ul> -<p><a href="https://geekyryan.com/wp-content/uploads/2015/08/5.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/5.png" alt=""></a></p> - + http://localhost:1313/posts/2015-08-13-error-when-reinstalling-dirsync/ + Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process: I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do: - Failed to Mount Exchange 2010 Database - https://rnemeth90.github.io/posts/2015-08-12-failed-to-mount-exchange-2010-database/ + http://localhost:1313/posts/2015-08-12-failed-to-mount-exchange-2010-database/ Wed, 12 Aug 2015 12:59:00 +0000 - - https://rnemeth90.github.io/posts/2015-08-12-failed-to-mount-exchange-2010-database/ - <p>Recently, one of my users’ came to me and said he was missing two months worth of email. This was just after migrating to Exchange Online. We were using Exchange 2010 with System Center DPM for backups.</p> -<p>I restored the database that the users’ mailbox was on from a backup then copied it over to the Exchange server from the network share I restored it to. All was going well, until I tried to mount the darn thing.</p> -<p>I was getting this error and could not for the life of me decry-pt the meaning of it. There is obviously some type of IO issue/file not found. But what could it be?</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/1-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/1-1.png" alt=""></a></p> -<p>I figured I’d better kick this one off with some basic troubleshooting. First, I checked the health of the database and made sure it was clean. Passed that test…</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/2-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/2-1.png" alt=""></a></p> -<p>Then ran a repair on the database, to no avail.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/3-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/3-1.png" alt=""></a></p> -<p>After racking my brain for a good thirty minutes, and a few failed Google searches, I found the solution. It was so simple! I created the log file directory in the folder with the database, and voila, the database mounted without a single error!</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/7.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/7.png" alt=""></a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/4-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/4-1.png" alt=""></a><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/5-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/5-1.png" alt=""></a></p> -<p>I was able to see the ‘supposed’ location of the log file by opening the Exchange Management Shell and running the ‘Get-MailboxDatabase’ cmdlet, like so:</p> -<p><em>Get-MailBoxDatabase –Identity <Recovery DB Name> | FL Name, ServerName, EDBFilePath, LogFolderPath</em></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/6.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/6.png" alt=""></a></p> -<p>I’m not sure why the database mounting process isn’t capable of creating the log file directory… I think Microsoft would have thought and planned for a situation like this. Hope this helps!</p> - + http://localhost:1313/posts/2015-08-12-failed-to-mount-exchange-2010-database/ + Recently, one of my users’ came to me and said he was missing two months worth of email. This was just after migrating to Exchange Online. We were using Exchange 2010 with System Center DPM for backups. I restored the database that the users’ mailbox was on from a backup then copied it over to the Exchange server from the network share I restored it to. All was going well, until I tried to mount the darn thing. - Ping Sweeping with FPing - https://rnemeth90.github.io/posts/2015-03-09-ping-sweeping-with-fping/ + http://localhost:1313/posts/2015-03-09-ping-sweeping-with-fping/ Mon, 09 Mar 2015 01:08:00 +0000 - - https://rnemeth90.github.io/posts/2015-03-09-ping-sweeping-with-fping/ - <p>I generally use NMAP for any type of host discovery, but recently started experimenting with FPing. One thing I found is that, when performing a ping sweep, not only do I see the hosts that replied to the ping, but FPing also sends any unreachable IP addresses to stdout (which is super annoying and ugly if you ask me…).</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h04_50.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h04_50.png" alt=""></a></p> -<p>Anyway, after a bit of research, I found a nifty way to suppress these messages. Linux allows us to redirect all error messages to /dev/null. So instead of just running the vanilla fping -a -g…. you would run the program and output all error messages /dev/null, like so:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h07_14.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h07_14.png" alt=""></a></p> - + http://localhost:1313/posts/2015-03-09-ping-sweeping-with-fping/ + I generally use NMAP for any type of host discovery, but recently started experimenting with FPing. One thing I found is that, when performing a ping sweep, not only do I see the hosts that replied to the ping, but FPing also sends any unreachable IP addresses to stdout (which is super annoying and ugly if you ask me…). Anyway, after a bit of research, I found a nifty way to suppress these messages. - Powershell: SID to Username - https://rnemeth90.github.io/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ + http://localhost:1313/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ Mon, 08 Dec 2014 13:43:00 +0000 - - https://rnemeth90.github.io/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ - <p>This is a simple script to convert a SID to a username</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span><span style="color:#75715e"># Returns a username based on a SID</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Author: Ryan Nemeth</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Date: 12/2/2014</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$SID = read-host <span style="color:#960050;background-color:#1e0010">“</span>Please enter the SID<span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#960050;background-color:#1e0010">”</span> -</span></span><span style="display:flex;"><span>$object = New-Object System.Security.Principal.SecurityIdentifier($SID) -</span></span><span style="display:flex;"><span>$User = $object.Translate( \[System.Security.Principal.NTAccount\]) -</span></span><span style="display:flex;"><span>write-host <span style="color:#960050;background-color:#1e0010">“</span>The user is<span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#960050;background-color:#1e0010">”</span> $User.Value -</span></span></code></pre></div> + http://localhost:1313/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ + This is a simple script to convert a SID to a username # Returns a username based on a SID # Author: Ryan Nemeth # Date: 12/2/2014 $SID = read-host “Please enter the SID: ” $object = New-Object System.Security.Principal.SecurityIdentifier($SID) $User = $object.Translate( \[System.Security.Principal.NTAccount\]) write-host “The user is: ” $User.Value - DHCP Address Negotiation Process - https://rnemeth90.github.io/posts/2014-12-08-dhcp-address-negotiation-process/ + http://localhost:1313/posts/2014-12-08-dhcp-address-negotiation-process/ Mon, 08 Dec 2014 03:08:00 +0000 - - https://rnemeth90.github.io/posts/2014-12-08-dhcp-address-negotiation-process/ - <p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/12/2014-12-07_22h07_33.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/12/2014-12-07_22h07_33.png" alt=""></a></p> - + http://localhost:1313/posts/2014-12-08-dhcp-address-negotiation-process/ + - Unlock a Domain User from CMD Line - https://rnemeth90.github.io/posts/2014-12-08-unlock-domain-user-from-cmd-line/ + http://localhost:1313/posts/2014-12-08-unlock-domain-user-from-cmd-line/ Mon, 08 Dec 2014 02:11:00 +0000 - - https://rnemeth90.github.io/posts/2014-12-08-unlock-domain-user-from-cmd-line/ - <p>To unlock a domain user from the command line, use this command:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>net user &amp;lt;username&amp;gt; /domain /active:yes -</span></span></code></pre></div><p>This can also be done using Powershell:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Unlock-ADAccount -identity <span style="color:#960050;background-color:#1e0010">“</span>CN=John,OU=myUsers,DC=myDomain,DC=local<span style="color:#960050;background-color:#1e0010">”</span> -</span></span></code></pre></div> + http://localhost:1313/posts/2014-12-08-unlock-domain-user-from-cmd-line/ + To unlock a domain user from the command line, use this command: net user &amp;lt;username&amp;gt; /domain /active:yes This can also be done using Powershell: Unlock-ADAccount -identity “CN=John,OU=myUsers,DC=myDomain,DC=local” - The Case of Transitive Trusts and Dropped RPC Connections - https://rnemeth90.github.io/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ + http://localhost:1313/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ Tue, 25 Nov 2014 01:27:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ - <p>I was at a client earlier this morning, working to get a transitive forest trust setup between their two domains. Setting up the trust on ServerA to DomainB went without issue. However, when trying to create the trust between ServerB and DomainA, I received this error: The secure channel reset on Active Directory Domain Controller (Your domain controller) of domain (Your domain) to domain (your other domain) failed with error: RPC server is unavailable.</p> -<p>Troubleshooting (as always) started off with the basics: is the firewall on or off, are the services running, are the names being properly resolved, etc. Well, the Windows Firewall on both servers was off and -the RPC services were running. So what now?? I fired up NMAP on ServerB and did a syn scan on ServerA. After reviewing the output, I could see that the ports were open. I then went over to ServerA and opened up the Services MSC console. The RPC services appeared to be running. Being that they are system services and you cannot manually interact with them, I was unable to manually restart them. Just out of curiosity,</p> -<p>I opened a command prompt while connected to that server and ran Netstat -A. This is when I had the “AHA!” moment. Nothing was listening on any of the RPC ports! I rebooted the server (something I don’t really like to do..), logged in and ran Netstat -A again. This time, RPC was listening. I went back over to ServerB, walked through the New Trust Wizard, and success! Oh, the feeling of victory!</p> - + http://localhost:1313/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ + I was at a client earlier this morning, working to get a transitive forest trust setup between their two domains. Setting up the trust on ServerA to DomainB went without issue. However, when trying to create the trust between ServerB and DomainA, I received this error: The secure channel reset on Active Directory Domain Controller (Your domain controller) of domain (Your domain) to domain (your other domain) failed with error: RPC server is unavailable. - Creating Applocker Policies - https://rnemeth90.github.io/posts/2014-11-17-creating-applocker-policies/ + http://localhost:1313/posts/2014-11-17-creating-applocker-policies/ Mon, 17 Nov 2014 01:40:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-17-creating-applocker-policies/ - <p>Application Control Policies can be used to restrict what programs a user is allowed to run. They can be created at the local Group Policy level or the Domain GPO level. There are 4 different types of Applocker RULES that you can implement, depending on what type of executable you want to control access to.</p> -<p>Executable Rules – EXE’s, COM’s, etc.</p> -<p>Script Rules – batch files, VB scripts, etc.</p> -<p>AppX Rules – AppX Packages (Windows 8.1/Server 2012 R2 Metro Interface programs)</p> -<p>Windows Installer Rules – Windows Installer Packages and MSU Packages</p> -<p>After choosing what type of executable file you want to control, you can choose the corresponding rule type. Then, you will be able to choose the criteria for that rule type. Applocker rule criteria are things such as file path, publisher, and file hash. Criteria allow you to be more granular with your selections. Rather than saying you want to block access to ALL executable’s on a computer, you can choose to block access to executable’s published by a certain vendor, or found in a specified directory.</p> -<p>Applocker can be found in the Group Policy Editor at: Computer Configuration\Windows Settings\Security Settings. Application Control Policies. By right-clicking on the Applocker node, you can configure rule enforcement. You have the option to enforce rules or audit rules based on rule type. Auditing will allow</p> -<p>you get a good grasp on what Applocker will do in your environment if you are unsure.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h18_31.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h18_31.png" alt=""></a></p> -<p>Clicking the Advanced tab of this window will allow you to configure rule enforcement for Dynamic Link Libraries. It’s best to leave DLL rule enforcement disabled, because it can cause a system to suffer dramatic performance hits.</p> -<p>Underneath the Applocker node, you will find nodes for the 4 different rule types. You can create new rules by right clicking on any of these nodes and clicking “Create New Rule”. Before creating any rules, I advise you to create the default rules. Doing this will ensure that users are still able to run programs in the Program Files directory and the Windows directory. Also, members of the built-in Administrators group will be allowed to run ANY files.</p> -<p>When creating custom Applocker rules, you can choose to allow or deny the program, and what group the rule will apply to (by default, the “Everyone” special identity is always selected).</p> -<p>You will also be able to choose the criteria for the executable that you are controlling.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h26_30.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h26_30.png" alt=""></a></p> -<p>If the executable has a digital signature from the software publisher, choose “Publisher”. Doing so will give you even more options:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h28_47.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h28_47.png" alt=""></a></p> -<p>This allows you to really drill down and get granular with the rule. Microsoft allows us to control access to the file based on the Publisher, the Product Name, the File Name, and even the File Version.</p> -<p>Creating rules based on File Path criteria is not advised, being that if the file jumps directories, the rule will no longer apply. I also don’t advise using the File Hash criteria. My reason behind this is, if the file gets updated, the hash changes. If that happens, the rule is no longer valid.</p> -<p>After choosing the criteria type you would like to use, you can choose to create exceptions, if any. When multiple rules conflict, the order of precedence is Publisher, File Hash, and then File Path. So Publisher rules will always override File Hash rules, File Hash rules will always override File Path rules, and you get the point…</p> -<p>Finally, in order for your endpoint workstations to process Applocker rules, the Application Identity Service must be running. I like to control this with the same GPO that I configure Applocker in.</p> - + http://localhost:1313/posts/2014-11-17-creating-applocker-policies/ + Application Control Policies can be used to restrict what programs a user is allowed to run. They can be created at the local Group Policy level or the Domain GPO level. There are 4 different types of Applocker RULES that you can implement, depending on what type of executable you want to control access to. Executable Rules – EXE’s, COM’s, etc. Script Rules – batch files, VB scripts, etc. AppX Rules – AppX Packages (Windows 8. - TCP/IP Network Fundamentals - https://rnemeth90.github.io/posts/2014-11-16-tcpip-network-fundamentals/ + http://localhost:1313/posts/2014-11-16-tcpip-network-fundamentals/ Sun, 16 Nov 2014 21:20:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-16-tcpip-network-fundamentals/ - <p>Going over the basics of network fundamentals and all the models and ideas behind them. The most pushed idea is the OSI networking model which consists of 7 layers, all of which deal with a certain aspect of the networking model.</p> -<p>A P S T N D P</p> -<p>From the top down this represents the following</p> -<p>Layer 7: Application – This layer is the channel between software and external requests. For example, a web server would work with this layer to process HTTP requests.</p> -<p>Layer 6: Presentation – This layer organizes data formats such as JPEG, Text, ASCII, etc</p> -<p>Layer 5: Session – This layer deals with session control; How a conversation should start, function, and end. It can be considered the broken between the layer below and the layers above. It will ensure all the data is proper when being passed up or down.</p> -<p>Layer 4: Transport – This layer is solely focused on data delivery. It deals with many protocols, but most notably it deals with TCP and UDP packets, any checksum errors, and error recovery</p> -<p>Layer 3: Network – This layer deals with logical addressing and routing. It deals with the actual delivery of packets across multiple networks.</p> -<p>Layer 2: Data Link – This layer deals with the rules of how data can be transmitted over a wire such as CSMA/CD and the like. It also deals with encapsulating frames to be transported over a local network</p> -<p>Layer 1: Physical – The actual hardware and electrical signaling to move data over the network. Network cards, cabling, and other hardware are part of this layer</p> -<p>Generic overview of the OSI model above lets work on the idea of some older and modern networks.</p> -<p>Hubs – Devices that simply take a signal and regenerate it out of all ports that are connected.</p> -<p>Switches – Devices that take a signal and make some sort of smart decision to provide a single path from one port to another</p> -<p>Routers – Devices that make decisions based upon higher level information (logical addressing) and will make intelligent decisions on how to handle that data, both incoming and outgoing. Segments networks into two different ones.</p> -<p>Bridge – A device that segments a network in two.</p> -<p>Collision Domain – The bounds where a collision may occur. This is relevant for networks utilizing half-duplex communication and for older devices such as hubs.</p> -<p>Broadcast Domain – The bounds where a broadcast can reach.</p> -<p>Collision Domains: Forgive the visio art, it will get better… hopefully</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h18_36.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h18_36.png" alt=""></a></p> -<p><a href="http://xenodez.pleasedonthack.us/?attachment_id=49">&lt;span style=&ldquo;color: windowtext; font-family: &ldquo;Verdana&rdquo;,sans-serif; font-size: 9.0pt; mso-no-proof: yes; text-decoration: none; text-underline: none;&quot;&gt;</a></p> -<p>Every computer connected to that hub is in the collision domain noted by the circle. With a hub, the signal gets sent to every device connected to it, regardless of whether it was meant to go to that machine or not. When the PC at the top left sends information at the same time as the PC on the bottom right, a collision is likely to occur</p> -<p><a href="http://xenodez.pleasedonthack.us/?attachment_id=52">&lt;span style=&ldquo;color: windowtext; font-family: &ldquo;Verdana&rdquo;,sans-serif; font-size: 9.0pt; mso-no-proof: yes; text-decoration: none; text-underline: none;&quot;&gt;</a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h18_45.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h18_45.png" alt=""></a></p> -<p>Every computer connected to this switch is limited in its collision domain to the port on the switch and the network card in the PC. The reason being that switches do not just take a signal and send it out of all the ports, it is intelligent enough to be able to send information directly to the PC it needs to. This is further mitigated by the fact that a computer connected to a switch may operate at full-duplex, allowing both simultaneous sending and receiving of information.</p> -<p>Collisions and how they are handled:</p> -<p>The way computers avoid collision in this sense is via something called CSMA/CD or Carrier Sense Multiple Access/Collision Avoidance. The way it works is this, a computer will wait until the line is silent before sending information. Every computer will listen to determine whether the line is truly clear. If two computers were to send at the same time, and a collision were to occur, the computers will immediately trigger a random back off time in which they will not try resending that information until the timer is up.</p> -<p>Unicast vs Broadcast vs Multicast</p> -<p>The idea between these concepts is fairly simple. Unicast deals with a transmission that is intended for one recipient. A broadcast is a transmission that is meant for all recipients that are able to hear it. Multicast is intended for a specific group of recipients.</p> - + http://localhost:1313/posts/2014-11-16-tcpip-network-fundamentals/ + Going over the basics of network fundamentals and all the models and ideas behind them. The most pushed idea is the OSI networking model which consists of 7 layers, all of which deal with a certain aspect of the networking model. A P S T N D P From the top down this represents the following Layer 7: Application – This layer is the channel between software and external requests. For example, a web server would work with this layer to process HTTP requests. - BranchCache - https://rnemeth90.github.io/posts/2014-11-16-branchcache/ + http://localhost:1313/posts/2014-11-16-branchcache/ Sun, 16 Nov 2014 21:16:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-16-branchcache/ - <p>Branchcache is a technology unique to Windows 7 and Windows Server 2008 R2. It provides faster connection to shared files across wide area networks. Branchcache works by caching content hosted on remote servers on a local caching server in the LAN. When a client queries for data on a remote server, it first looks in the local caching server. If the data is not found there, the remote server is accessed and transfer’s the data to the local caching server, where it is then accessed by the client who originally made the request. That way, all future client requests will not have to go across the wide area network, rather opting to access the local caching server until the data changes.</p> -<p>Branchcache is only available on Windows 7 clients running Enterprise or Ultimate, and Windows Server 2008 R2. Branchcache becomes active when the round trip latency time from client to remote server exceeds 80 milliseconds.</p> -<p>Branchcache is available in two modes: distributed cache mode and hosted cache mode. What you just read above was the basics of hosted cached mode. Distributed cache mode works differently to achieve the same results. When a client accesses data across the WAN, it stores that data in its own cache. This way, if another client needs access to the data, it can retrieve it locally. Also, this allows each client to host part of the cache, rather than one machine hosting the entire cache.</p> -<p>There are two steps to configuring Branchcache on a Windows 7 client. I will not include the server configuration at this point in time.</p> -<p>Enable Branchcache (Hosted or Distributed, Server 08 R2 will be required for Hosted mode)</p> -<p>Configure the appropriate ports within the Windows Firewall</p> -<p>You can enable Branchcache from within Group Policy or by using the Netsh command. When using Group Policy, navigate to Computer Configuration &gt; Administrative Templates &gt; Network &gt; Branchcache. From here you can turn on Branchcache and enable the mode you want to use. You can also set the percentage of disk space to be used for caching. After this, open the Windows Firewall and unblock the Branchcache ports. You only need to do this when configuring Branchcache via Group Policy. Using the Netsh command automatically configures the firewall. Here are the basic commands for Netsh:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>Netsh Branchcache set service mode<span style="color:#f92672">=</span>distributed -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Netsh Branchcache reset -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Netsh Branchcache show status -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Netsh Branchcache set cachesize -</span></span></code></pre></div><p>*Configuring Branchcache must be done from an administrative command prompt.</p> - + http://localhost:1313/posts/2014-11-16-branchcache/ + Branchcache is a technology unique to Windows 7 and Windows Server 2008 R2. It provides faster connection to shared files across wide area networks. Branchcache works by caching content hosted on remote servers on a local caching server in the LAN. When a client queries for data on a remote server, it first looks in the local caching server. If the data is not found there, the remote server is accessed and transfer’s the data to the local caching server, where it is then accessed by the client who originally made the request. - File History - https://rnemeth90.github.io/posts/2014-11-15-file-history/ + http://localhost:1313/posts/2014-11-15-file-history/ Sat, 15 Nov 2014 20:02:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-15-file-history/ - <p>File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. To begin using it, connect an external drive and search for File History on the Start Screen:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-15_14h19_47.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-15_14h19_47.png" alt=""></a></p> -<p>After opening File History, you will see this screen:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-15_14h20_32.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-15_14h20_32.png" alt=""></a></p> -<p>To enable File History, click the ‘Turn On’ button. You can select the drive you want to use by clicking ‘Select Drive’ on the left hand side from this same screen. The first time you enable File History, it will create a full backup of all files on your computer, except for files that you do not access (system files), and files you have chosen to exclude. From then on, it will create a versioned copy of every file that has changed since the last backup.</p> -<p>You can use a locally attached drive or a network share for File History. To choose how often File History backs up files; choose ‘Advanced Settings’. From here you can also choose how much space on the drive is used, and how long saved versions of files should be kept.</p> -<p>When the total space allocated to File History has been used, the feature will delete the oldest versions of files to make room for newer versions.</p> - + http://localhost:1313/posts/2014-11-15-file-history/ + File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. - User Account Control - https://rnemeth90.github.io/posts/2012-11-15-user-account-control-copy/ + http://localhost:1313/posts/2012-11-15-user-account-control-copy/ Thu, 15 Nov 2012 16:01:00 +0000 - - https://rnemeth90.github.io/posts/2012-11-15-user-account-control-copy/ - <p>Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system.</p> -<p>For a standard user, a token with the most basic privileges is assigned. Administrators have two tokens assigned, the first token contains all privileges usually awarded to an administrator (unrestricted), and the second is similar to that awarded to a basic user. This way, all programs that the administrator runs, including the Windows Shell, are run in basic user mode (this is why administrators still receive UAC prompts, but do not get asked for credentials). When an application requests higher privileges, the higher integrity token is used .</p> -<p>User Account Control prompts each have their own meaning based on the color (blue, grey, yellow, or red. The blue prompt (Figure 1) means that a built in Windows component that is signed by Microsoft is requesting administrative privileges to continue. This prompt has a multicolored shield in the upper left corner. The grey prompt (Figure 2) means a software application that is signed by a third party developer is requesting admin privileges. This prompt has a yellow shield with a black exclamation mark in the upper left corner. The yellow prompt (Figure 3) signifies that a unsigned executable is requesting administrator privileges. This prompt also had a yellow shield with black exclamation mark in the upper left corner, and looks somewhat generic. Finally, the red prompt (Figure 4) means a program that was specifically blocked by an administrator has attempted to run.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BBlue.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BBlue.png" alt=""></a></p> -<p>Figure 1</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BGrey.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BGrey.png" alt=""></a></p> -<p>Figure 2</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BYellow.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BYellow.png" alt=""></a></p> -<p>Figure 3</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BRED.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BRED.png" alt=""></a></p> -<p>Figure 4</p> - + http://localhost:1313/posts/2012-11-15-user-account-control-copy/ + Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system. - User Account Control - https://rnemeth90.github.io/posts/2012-11-15-user-account-control/ + http://localhost:1313/posts/2012-11-15-user-account-control/ Thu, 15 Nov 2012 16:01:00 +0000 - - https://rnemeth90.github.io/posts/2012-11-15-user-account-control/ - <p>Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system.</p> -<p>For a standard user, a token with the most basic privileges is assigned. Administrators have two tokens assigned, the first token contains all privileges usually awarded to an administrator (unrestricted), and the second is similar to that awarded to a basic user. This way, all programs that the administrator runs, including the Windows Shell, are run in basic user mode (this is why administrators still receive UAC prompts, but do not get asked for credentials). When an application requests higher privileges, the higher integrity token is used.</p> -<p>User Account Control prompts each have their own meaning based on the color (blue, grey, yellow, or red. The blue prompt (Figure 1) means that a built in Windows component that is signed by Microsoft is requesting administrative privileges to continue. This prompt has a multicolored shield in the upper left corner. The grey prompt (Figure 2) means a software application that is signed by a third party developer is requesting admin privileges. This prompt has a yellow shield with a black exclamation mark in the upper left corner. The yellow prompt (Figure 3) signifies that a unsigned executable is requesting administrator privileges. This prompt also had a yellow shield with black exclamation mark in the upper left corner, and looks somewhat generic. Finally, the red prompt (Figure 4) means a program that was specifically blocked by an administrator has attempted to run.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BBlue.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BBlue.png" alt=""></a></p> -<p>Figure 1</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BGrey.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BGrey.png" alt=""></a></p> -<p>Figure 2</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BYellow.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BYellow.png" alt=""></a></p> -<p>Figure 3</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BRED.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BRED.png" alt=""></a></p> -<p>Figure 4</p> - + http://localhost:1313/posts/2012-11-15-user-account-control/ + Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system. - diff --git a/public/categories/uncategorized/page/1/index.html b/public/categories/uncategorized/page/1/index.html index 56f32314..4b8514fc 100644 --- a/public/categories/uncategorized/page/1/index.html +++ b/public/categories/uncategorized/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/categories/uncategorized/ - + http://localhost:1313/categories/uncategorized/ + - + diff --git a/public/categories/uncategorized/page/2/index.html b/public/categories/uncategorized/page/2/index.html index 28be793e..c6da4668 100644 --- a/public/categories/uncategorized/page/2/index.html +++ b/public/categories/uncategorized/page/2/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: Uncategorized · GeekyRyan + - + -Uncategorized - GeekyRyan - + + + - - - + + + + + + + + + - - - - - + + + + - - - - - - - - - - - - - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,848 +79,267 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - - -
    -
    - -

    Category: Uncategorized

    - - - -
    -
    -
    -

    Deploy a New ADDS Forest on Server 2019 Core

    -
    - -
    - - -
    - Prerequisites: -Change server name and IP address Configure time settings and NTP -In this post we will be reviewing the basic installation of the Active Directory Domain Services role and setup of a new forest on Windows Server Core 2019. -To get started, login to your server with administrator privileges. You will first need to type in “powershell” in the cmd prompt to start powershell. Once you do that, type in the following command to install the Active Directory Domain Services role: -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Could not connect to VMware Directory Service via LDAP when Deploying New vCenter Appliance

    -
    - -
    - - -
    - Problem: -Deploying a brand new vCSA 6.7 appliance results in the following error during the second stage of the deployment. -Solution: -This problem is almost always caused by DNS resolution. Once you create the appropriate A and PTR record for your appliance on a LOCAL DNS server, you should be to successfully complete the deployment. Local DNS resolution is required, you cannot use a public DNS server while installing vCenter. For example, 8. -
    - - -
    - Read more -
    - - - - - - -
    - -
    -
    -
    -

    Cisco AnyConnect &#8211; VPN Establishment Capability from a Remote Desktop is Disabled

    -
    - -
    - - -
    - I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution. -Upon installation, AnyConnect pulls down a profile from the ASA containing several settings. This profile is in xml format and is located (on a Windows machine) at %programdata%CiscoCisco AnyConnect Secure Mobility ClientProfileAnyConnectProfile.xsd. -To resolve this issue and connect to your VPN, open this file with notepad (or any text editor, run as admin), search for the “WindowsVPNEstablishment” tag, and modify the value. -
    - - -
    - Read more -
    - - - - - - - -
    - -
    -
    -
    -

    Active Directory Migration Toolkit &#8211; The RPC Server is Unavailable (hr=0x800706ba)

    -
    - -
    - - -
    - When migrating computer objects using the Active Directory Migration Tool, you may encounter the following error: -In addition, the Migration Log may show the following error: -This is typically caused by a host-side firewall. To resolve this, deploy a GPO to disable the Windows firewall prior to migrating the computer account. I like to create a special OU for computers (I typically name it “PreMigration”) that I will move computer objects to prior to migrating them. -
    - - -
    - Read more -
    - - - +
    + + + +
    + +
    +
    +

    + Category: Uncategorized +

    +
    + +
    +
  • + 2020-10-31 + Deploy a New ADDS Forest on Server 2019 Core +
  • -
    -
    -
    -

    Azure Site Recovery &#8211; VMware-to-Azure: Wrong IP address discovered for VM

    -
    - -
    - +
  • + 2020-10-28 + Could not connect to VMware Directory Service via LDAP when Deploying New vCenter Appliance +
  • -
    - When replicating virtual machines from VMware to Azure using Site Recovery, you may encounter an issue where the Configuration server discovers the wrong IP address for a VM. This can be caused by stale entries within the infrastructurevms MySQL table that is used by ASR to track VM attributes. -To resolve this issue, you first need to disable replication for the VM in the Azure Portal. -Next, login to your ASR Configuration Server and open a CMD prompt as administrator. -
    +
  • + 2020-10-07 + Cisco AnyConnect &#8211; VPN Establishment Capability from a Remote Desktop is Disabled +
  • +
  • + 2018-08-21 + Active Directory Migration Toolkit &#8211; The RPC Server is Unavailable (hr=0x800706ba) +
  • -
    - Read more -
    +
  • + 2018-08-21 + Azure Site Recovery &#8211; VMware-to-Azure: Wrong IP address discovered for VM +
  • +
  • + 2018-07-26 + Azure AD Connect No-Start-Connection +
  • +
  • + 2018-07-18 + Azure AD Connect Health: Latest Data is not Available in Azure Portal +
  • - +
  • + 2018-07-13 + Removing a Forest from Azure AD Connect +
  • - - - -
    - -
    -
    -
    -

    Azure AD Connect No-Start-Connection

    -
    - -
    +
    + -
    -
    -
    -

    Azure AD Connect Health: Latest Data is not Available in Azure Portal

    -
    - -
    - -
    - I recently had to create a new Azure AD Connect server, and found that it was not able to report health status in the Azure Portal. After some troubleshooting/research, I was able to get the health status report working by registering the health agent on the server with Azure AD Health Services. Doing this involves running one PowerShell cmdlet on your AD Connect server and providing global administrator credentials. -First, let’s test the status of the agent communication: -
    + +
  • 2
  • + + -
    - Read more -
    + - + +
  • 3
  • + - - - - -
    + -
    -
    -
    -

    Removing a Forest from Azure AD Connect

    -
    - -
    - -
    - In an organization with multiple Active Directory forests, you may want to sync objects from trusted forests. Adding trusted forests to Azure AD Sync is a simple process that I will likely cover in a future article. The focus of this post is the not-so-obvious process of removing a forest from Azure AD Connect. This can be a daunting and somewhat scary thing to do. Not fully understanding the process or having someone to guide you can leave you with thoughts like “what happens when I remove the forest from Azure AD Sync? -
    + +
  • 4
  • + + -
    - Read more -
    + - + +
  • 5
  • + - - - -
    - -
    -
    -
    -

    Remove Stubborn PSC or vCenter Appliance from an SSO Domain

    -
    -
    +
    +
    + © -
    - While attempting to decommission one of our vCenter sites, I ran into an issue removing one of the PSCs. This site consisted of two PSCs and one vCenter appliance. I removed the first PSC from the SSO domain successfully, and then removed the vCenter appliance. Things became a little tricky during the removal of the final PSC. This PSC did not get removed even after running the cmsso-util command. This article will detail the steps I took in decommissioning the site, as well as removing the stubborn PSC. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    -
    - - - - - - -
    -
    - - - -
    -
    -
    -

    Exchange 2016 Hybrid Deploy Check: Username or Password Invalid

    -
    - -
    + - -
    - These days, it seems every Microsoft product comes with its own unique set of head scratchers. Microsoft Exchange Server is no exception to this. I was installing Exchange 2016 earlier today, to be used as a hybrid configuration server for Office 365 (no local mailboxes). I downloaded the self depackaging executable from Microsoft, and attempted to install it. If you currently have a hybrid configuration (which we did, with Exchange 2010), the Exchange 2016 installer will detect this and run some tests to verify that the Office 365 tenant is ready for Exchange 2016 (more info here: https://technet. -
    - - -
    - Read more -
    - - - + + + + - + + -
    - - - - https://rnemeth90.github.io/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ - Ryan + + -
    - - - - - - -
    -
    -
    - - - - - + + + + - - - + - - + + diff --git a/public/categories/uncategorized/page/3/index.html b/public/categories/uncategorized/page/3/index.html index 3e1d52dc..5ccc7aa7 100644 --- a/public/categories/uncategorized/page/3/index.html +++ b/public/categories/uncategorized/page/3/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: Uncategorized · GeekyRyan + - + -Uncategorized - GeekyRyan - + + + - - - + + + + + + + + + - - - - - + + + + - - - - - - - - - - - - - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,823 +79,267 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - - -
    -
    - -

    Category: Uncategorized

    - - - -
    -
    -
    -

    Migrate Windows Deployment Services to New Server

    -
    - -
    - - -
    - We have been making a great effort to move all of our internal services to Windows Server 2016. This past week, it was WDS’ turn to get migrated. Migrating this role is extremely simple. Here are the steps that I took: -Create new server and install WDS role. Stop WDS Service on old server Stop WDS Service on new server Use my “Copy-Files” PowerShell script (Available Here: Copy-Files.ps1) to copy RemoteInstall Share to new server Start WDS Service on new Server Shutdown old WDS Server completely Update option 66/67 in DHCP scopes to reflect new WDS Server Update any appropriate DNS records Note: -
    - - -
    - Read more -
    - - - - - - - - - -
    - - - -
    -
    -
    -

    Windows 8 File History

    -
    - -
    - - -
    - File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. -
    - - -
    - Read more -
    - - - - - - - -
    - -
    -
    -
    -

    How to Permanently Remove Office 365 Users

    -
    - -
    - - -
    - After deleting a user in Office 365, their account is moved to a ‘recycle bin’ for 30 days. This allows the user account to be easily recovered. This can often cause issues when attempting to recreate a mailbox while a hybrid configuration is in place. -To permanently delete the user within Office 365, first delete the user in the Office 365 Admin Portal or using Powershell. Then, connect to your Azure Active Directory environment with Powershell using the “Connect-MsolService” cmdlet. -
    - - -
    - Read more -
    - - - - - - -
    +
  • + 2017-06-27 + Migrate Windows Deployment Services to New Server +
  • -
    -
    -
    -

    Access is Denied When Attempting to Delete a Dynamic Distribution Group

    -
    - -
    - +
  • + 2017-06-26 + New Script: BulkAdd-SpamFilterWhitelist.ps1 +
  • -
    - You may receive the error below when attempting to delete a dynamic distribution group. -To resolve this, open ADUC and show advanced features (Click View > Advanced Features). Then find the object for the dynamic distribution group and open the properties window. Browse to the “Object” tab and uncheck the “Protect object from accidental deletion” box. Wait for ADDS to replicate or force replication yourself. -Go back to the ECP and you should be able to delete the group. -
    +
  • + 2017-06-22 + Windows 8 File History +
  • +
  • + 2017-06-20 + How to Permanently Remove Office 365 Users +
  • -
    - Read more -
    +
  • + 2017-06-12 + Access is Denied When Attempting to Delete a Dynamic Distribution Group +
  • +
  • + 2017-05-29 + Running vSphere in VMware Workstation 12 +
  • +
  • + 2016-11-18 + WSUS: Update Files Not Downloading (Content File Download Failed) +
  • - +
  • + 2016-11-10 + WSUS: An error occurred trying to connect the WSUS server +
  • - - - -
    - -
    -
    -
    -

    Running vSphere in VMware Workstation 12

    -
    - -
    +
      + -
      - In this post I’ll be walking through how to run a vSphere lab in VMware Workstation. I recently decided to obtain VCP6-DCV. Rather than driving up my electric bill like I’ve done in the past using physical servers, I’m attempting to run the entire lab on my workstation and a Synology NAS. -If you’ve ever installed ESXi, installing it in Workstation will be a familiar process for you. VMware tools is included in the installation disc, which makes installing ESXi in Workstation dramatically easier than it used to be. -
      +
    • «
    • + + + -
      - Read more -
      + - + +
    • 1
    • + - - - - -
    + -
    -
    -
    -

    WSUS: Update Files Not Downloading (Content File Download Failed)

    -
    - -
    - -
    - This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates: -You may also see this event (or similar) in the Event Log. -This problem is caused by not specifying a valid path when assigning the WSUS content drive when first installing the role. The first time you load the WSUS console after installing the role, you will be prompted to specify the path to store Windows Update files. -
    + +
  • 2
  • + + -
    - Read more -
    + - + +
  • 3
  • + - - - - -
    + -
    -
    -
    -

    WSUS: An error occurred trying to connect the WSUS server

    -
    - -
    - -
    - Ran into this error message when configuring a new WSUS server: -Restarted the WSUS, WID, and IIS services to no avail. I even rebooted the server. The WSUS console would work for a short period of time, and then would randomly stop working. -I found that the WSUS app pool in IIS was being disabled anytime new clients connected to the server. I believe this was because the app pool was running out of usable memory. -
    + +
  • 4
  • + + -
    - Read more -
    + - + +
  • 5
  • + - - - -
    - -
    -
    -
    -

    WDS Service: The Service did not respond in a timely fashion

    -
    -
    +
    +
    + © -
    - This was a new one for me. Usually WDS is rock solid and it just works. -Anyway, I was getting ready to deploy some servers in my lab and found that I couldn’t get WDS to start on my deployment server. I got this error message when trying to start the service: -I then tried to start the service from the Services console and got this error message: -“This was just working yesterday”, I said to myself. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - - -
    +
    +
    -
    - - - - - - -
    -
    - - - -
    -
    -
    -

    Script to Move All Disabled AD Objects to a Specified OU

    -
    - -
    + - -
    - The title says it all. This script will move all disabled AD objects to a specified OU. This script accepts parameters that will allow you to specify whether you want to move Users or Computers and the destination OU. It also accepts a “test mode” parameter that will run the script and output the results, without actually modifying Active Directory. -This is revision 1 of the script. There are still several improvements I would like to make, including better error handling and recovery. -
    - - -
    - Read more -
    - - - + + + + - + + -
    - - - - https://rnemeth90.github.io/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ - Ryan + + -
    - - - - - - -
    -
    -
    - - - - - + + + + - - - + - - + + diff --git a/public/categories/uncategorized/page/4/index.html b/public/categories/uncategorized/page/4/index.html index c307f2dd..2df4bccc 100644 --- a/public/categories/uncategorized/page/4/index.html +++ b/public/categories/uncategorized/page/4/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: Uncategorized · GeekyRyan + - + -Uncategorized - GeekyRyan - + + + - - - + + + + + + + + + - - - - - + + + + - - - - - - - - - - - - - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,837 +79,267 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - - -
    -
    - -

    Category: Uncategorized

    - - - -
    -
    -
    -

    Script for Setting the License for Multiple Office 365 User Accounts

    -
    - -
    - - -
    - A script for setting the Office 365 license for multiple users. Requires a CSV file named users.csv. This file must in the same directory as the script. The CSV file must contain three columns. The title of the columns should be UPN, UsageLocation, and SKU. -BulkSet-MsolUserLicense.ps1 -
    - - - - - - - - - - -
    - -
    -
    -
    -

    The User Profile Service service failed the logon

    -
    - -
    - - -
    - One of my clients had a really strange issue the other day. He has a domain admin account in his domain and was not able to login to a server that I recently built. The server was an Exchange 2013 box, and was used in Coexistence mode to migrate his company from an Exchange 2007 box. -He was getting this error message when attempting to login: -This is a classic error message that I’m sure most technicians have seen before. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Azure AD Connect Password Sync &#8211; Disabled and Grayed Out

    -
    - -
    - - -
    - Ran into a problem earlier with the new Azure AD Connect Wizard. We had configured the wizard and synced around 500 AD accounts. However, password sync was not working. I opened the wizard to confirm the configuration and found that “Password Hash Synchronization” was disabled. It was greyed out and could not be enabled. -I called Microsoft and worked for a couple hours with a technician to resolve the issue. Thought I should post the resolution here in case anyone else encounters this. -
    - - -
    - Read more -
    - - - - - - - -
    - -
    -
    -
    -

    Finding All Mailboxes with a Forwarding Address in Exchange 2003

    -
    - -
    - - -
    - Believe it or not, the MSP I work for still has a client who is using Exchange 2003 as their primary email service. Despite several attempts at convincing them of the power of Office 365, they refuse to migrate. Last week the CFO contacted me and requested we provide them with a report of all users who have their email forwarded to another mailbox. “Ok, no problem.” I said helpfully as the client informed me of their request (at the time I didn’t even think about them having Exchange 2003…). -
    - - -
    - Read more -
    - - - +
    + + + +
    +
  • + 2015-10-15 + Azure AD Connect Password Sync &#8211; Disabled and Grayed Out +
  • -
    -
    -
    -

    Script for Querying All AD Computers Time Source

    -
    - -
    - +
  • + 2015-09-07 + Finding All Mailboxes with a Forwarding Address in Exchange 2003 +
  • -
    - This script will iterate through all computers in Active Directory and return the configured time server for each computer. -<# .SYNOPSIS Get time source for all computers in domain .EXAMPLE Get-TimeSource .NOTES Author: Ryan Nemeth - RyanNemeth@live.com Site: http://www.geekyryan.com .LINK http://www.geekyryan.com .DESCRIPTION This function will iterate through all computers/servers in a domain and return the time source for each. #> Write-Host -foregroundcolor Red -BackgroundColor black "This script must be run on a domain controller and requires that the AD Powershell module be installed" $module = Get-Module -ListAvailable | Select-Object -ExpandProperty Name if($module -notcontains "ActiveDirectory") { Write-Host -foregroundcolor red -backgroundcolor black "***Active Directory Powershell Module Not Found***" } else { Write-Host -foregroundcolor yellow "Found Active Directory Powershell Module. -
    +
  • + 2015-09-01 + Script for Querying All AD Computers Time Source +
  • +
  • + 2015-08-13 + Error When Reinstalling DirSync +
  • -
    - Read more -
    +
  • + 2015-08-12 + Failed to Mount Exchange 2010 Database +
  • +
  • + 2015-03-09 + Ping Sweeping with FPing +
  • +
  • + 2014-12-08 + Powershell: SID to Username +
  • - +
  • + 2014-12-08 + DHCP Address Negotiation Process +
  • + + - - -
    - -
    -
    -
    -

    Error When Reinstalling DirSync

    -
    - -
    - +
      + -
      - Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process: -I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do: -
      +
    • «
    • + + + -
      - Read more -
      + - + +
    • 1
    • + - - - - -
    + -
    -
    -
    -

    Failed to Mount Exchange 2010 Database

    -
    - -
    - -
    - Recently, one of my users’ came to me and said he was missing two months worth of email. This was just after migrating to Exchange Online. We were using Exchange 2010 with System Center DPM for backups. -I restored the database that the users’ mailbox was on from a backup then copied it over to the Exchange server from the network share I restored it to. All was going well, until I tried to mount the darn thing. -
    + +
  • 2
  • + + -
    - Read more -
    + - + +
  • 3
  • + - - - - -
    + -
    -
    -
    -

    Ping Sweeping with FPing

    -
    - -
    - -
    - I generally use NMAP for any type of host discovery, but recently started experimenting with FPing. One thing I found is that, when performing a ping sweep, not only do I see the hosts that replied to the ping, but FPing also sends any unreachable IP addresses to stdout (which is super annoying and ugly if you ask me…). -Anyway, after a bit of research, I found a nifty way to suppress these messages. -
    + +
  • 4
  • + + -
    - Read more -
    + - + +
  • 5
  • + - - - -
    - -
    -
    -
    -

    Powershell: SID to Username

    -
    -
    +
    +
    + © -
    - This is a simple script to convert a SID to a username -# Returns a username based on a SID # Author: Ryan Nemeth # Date: 12/2/2014 $SID = read-host “Please enter the SID: ” $object = New-Object System.Security.Principal.SecurityIdentifier($SID) $User = $object.Translate( \[System.Security.Principal.NTAccount\]) write-host “The user is: ” $User.Value -
    - + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    -
    - - - - - - -
    -
    - - - -
    -
    -
    -

    DHCP Address Negotiation Process

    -
    - -
    + - -
    - -
    - - - - + + + + - + + -
    - - - - https://rnemeth90.github.io/posts/2014-12-08-dhcp-address-negotiation-process/ - Ryan + + -
    - - - - - - -
    -
    -
    - - - - - + + + + - - - + - - + + diff --git a/public/categories/uncategorized/page/5/index.html b/public/categories/uncategorized/page/5/index.html index c65ee0b2..69e68ba4 100644 --- a/public/categories/uncategorized/page/5/index.html +++ b/public/categories/uncategorized/page/5/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Category: Uncategorized · GeekyRyan + - - -Uncategorized - GeekyRyan - - - - - - + - - - - - + + + - + + + + + + + + + - - - - - - - - - + + + + + + + - - - + - - - - - - - - - - + + + - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,690 +79,252 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - - -
    -
    - -

    Category: Uncategorized

    - - - -
    -
    -
    -

    Unlock a Domain User from CMD Line

    -
    - -
    - - -
    - To unlock a domain user from the command line, use this command: -net user &lt;username&gt; /domain /active:yes This can also be done using Powershell: -Unlock-ADAccount -identity “CN=John,OU=myUsers,DC=myDomain,DC=local” -
    - - - - - - - - - - -
    - -
    -
    -
    -

    The Case of Transitive Trusts and Dropped RPC Connections

    -
    - -
    - -
    - I was at a client earlier this morning, working to get a transitive forest trust setup between their two domains. Setting up the trust on ServerA to DomainB went without issue. However, when trying to create the trust between ServerB and DomainA, I received this error: The secure channel reset on Active Directory Domain Controller (Your domain controller) of domain (Your domain) to domain (your other domain) failed with error: RPC server is unavailable. -
    - - -
    - Read more -
    - - - - - - -
    - -
    -
    -
    -

    Creating Applocker Policies

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Category: Uncategorized +

    +
    + + + - https://rnemeth90.github.io/posts/2014-11-17-creating-applocker-policies/ - Ryan -
    - - - - - - -
    -
    -
    - -
    -
    -
    -

    TCP/IP Network Fundamentals

    -
    - -
    +
      + -
      - Going over the basics of network fundamentals and all the models and ideas behind them. The most pushed idea is the OSI networking model which consists of 7 layers, all of which deal with a certain aspect of the networking model. -A P S T N D P -From the top down this represents the following -Layer 7: Application – This layer is the channel between software and external requests. For example, a web server would work with this layer to process HTTP requests. -
      +
    • «
    • + + + -
      - Read more -
      + - + +
    • 1
    • + - - - - -
    + -
    -
    -
    -

    BranchCache

    -
    - -
    - -
    - Branchcache is a technology unique to Windows 7 and Windows Server 2008 R2. It provides faster connection to shared files across wide area networks. Branchcache works by caching content hosted on remote servers on a local caching server in the LAN. When a client queries for data on a remote server, it first looks in the local caching server. If the data is not found there, the remote server is accessed and transfer’s the data to the local caching server, where it is then accessed by the client who originally made the request. -
    + -
    - Read more -
    + +
  • 2
  • + + - + - - - - -
    + -
    -
    -
    -

    File History

    -
    - -
    - -
    - File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. -
    + -
    - Read more -
    + +
  • 4
  • + + - + - - - -
    - -
    -
    -
    -

    User Account Control

    -
    -
    +
    +
    + © -
    - Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system. -
    - - -
    - Read more -
    - + 2012 - + 2024 + Ryan Nemeth + · - - - - -
    +
    - https://rnemeth90.github.io/posts/2012-11-15-user-account-control-copy/ - Ryan - - -
    - - - - - - -
    -
    + - - -
    -
    -
    -

    User Account Control

    -
    - -
    + - -
    - Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system. -
    - - -
    - Read more -
    - - - + + + + - + + -
    - - - - https://rnemeth90.github.io/posts/2012-11-15-user-account-control/ - Ryan + + -
    - - - - - - -
    -
    -
    - - - - - + + + + - - - + - - + + diff --git a/public/categories/web-development/index.html b/public/categories/web-development/index.html new file mode 100644 index 00000000..acce247b --- /dev/null +++ b/public/categories/web-development/index.html @@ -0,0 +1,239 @@ + + + + + Category: Web Development · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + +
    + + + +
    + +
    +
    +

    + Category: Web Development +

    +
    + + + + + + + + + +
    + + +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/categories/web-development/index.xml b/public/categories/web-development/index.xml new file mode 100644 index 00000000..a6c53eee --- /dev/null +++ b/public/categories/web-development/index.xml @@ -0,0 +1,26 @@ + + + + Web Development on GeekyRyan + http://localhost:1313/categories/web-development/ + Recent content in Web Development on GeekyRyan + Hugo + en + Wed, 27 Mar 2024 00:00:00 +0000 + + + Detecting MIME Types in Go + http://localhost:1313/posts/2024-03-27-golang-detect-file-type/ + Wed, 27 Mar 2024 00:00:00 +0000 + http://localhost:1313/posts/2024-03-27-golang-detect-file-type/ + Introduction Link to heading Knowing the type of a file you&rsquo;re working with is not just a matter of curiosity — it&rsquo;s often a necessity. This is especially true when you&rsquo;re deciding whether or not a particular operation can be carried out on that file. Go, with its comprehensive standard library, offers a straightforward approach to identifying a file&rsquo;s MIME type, ensuring that developers have the tools they need to make informed decisions about file manipulation. + + + Validating URLs with Go + http://localhost:1313/posts/2023-12-12-golang-url-validation/ + Tue, 19 Dec 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-12-12-golang-url-validation/ + Introduction Link to heading In this post, we&rsquo;ll take a quick look at URL validation using Golang. It&rsquo;s common to implement URL validation as a task within a HTTP request pipeline, typically as middleware. There are many different definitions of &ldquo;validation&rdquo;. For the purpose of this article, we will simply validate that a URL conforms to a particular text pattern. I often see people (mistakenly) use URL and URI interchangeably. + + + diff --git a/public/categories/web-development/page/1/index.html b/public/categories/web-development/page/1/index.html new file mode 100644 index 00000000..d9f40f36 --- /dev/null +++ b/public/categories/web-development/page/1/index.html @@ -0,0 +1,10 @@ + + + + http://localhost:1313/categories/web-development/ + + + + + + diff --git a/public/css/coder-dark.css b/public/css/coder-dark.css new file mode 100644 index 00000000..9495c4af --- /dev/null +++ b/public/css/coder-dark.css @@ -0,0 +1,835 @@ +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 pre code { + background-color: inherit; + color: inherit; } + body.colorscheme-dark code { + background-color: #4f4f4f; + color: #dadada; } + body.colorscheme-dark blockquote { + border-left: 2px solid #424242; } + body.colorscheme-dark th, + body.colorscheme-dark td { + padding: 1.6rem; } + body.colorscheme-dark table { + border-collapse: collapse; } + body.colorscheme-dark table td, + body.colorscheme-dark table th { + border: 2px solid #dadada; } + body.colorscheme-dark table tr:first-child th { + border-top: 0; } + body.colorscheme-dark table tr:last-child td { + border-bottom: 0; } + body.colorscheme-dark table tr td:first-child, + body.colorscheme-dark table tr th:first-child { + border-left: 0; } + body.colorscheme-dark table tr td:last-child, + body.colorscheme-dark table tr th:last-child { + border-right: 0; } + +@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 pre code { + background-color: inherit; + color: inherit; } + body.colorscheme-auto code { + background-color: #4f4f4f; + color: #dadada; } + body.colorscheme-auto blockquote { + border-left: 2px solid #424242; } + body.colorscheme-auto th, + body.colorscheme-auto td { + padding: 1.6rem; } + body.colorscheme-auto table { + border-collapse: collapse; } + body.colorscheme-auto table td, + body.colorscheme-auto table th { + border: 2px solid #dadada; } + body.colorscheme-auto table tr:first-child th { + border-top: 0; } + body.colorscheme-auto table tr:last-child td { + border-bottom: 0; } + body.colorscheme-auto table tr td:first-child, + body.colorscheme-auto table tr th:first-child { + border-left: 0; } + body.colorscheme-auto table tr td:last-child, + body.colorscheme-auto table tr th:last-child { + border-right: 0; } } + +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 .tabs label.tab-label { + background-color: #424242; + border-color: #4f4f4f; } + +body.colorscheme-dark .tabs input.tab-input:checked + label.tab-label { + background-color: #212121; } + +body.colorscheme-dark .tabs .tab-content { + background-color: #212121; + border-color: #4f4f4f; } + +@media (prefers-color-scheme: dark) { + body.colorscheme-auto .tabs label.tab-label { + background-color: #424242; + border-color: #4f4f4f; } + body.colorscheme-auto .tabs input.tab-input:checked + label.tab-label { + background-color: #212121; } + body.colorscheme-auto .tabs .tab-content { + background-color: #212121; + border-color: #4f4f4f; } } + +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; } } +body.colorscheme-dark { + /* Background */ + /* PreWrapper */ + /* Other */ + /* Error */ + /* CodeLine */ + /* LineLink */ + /* LineTableTD */ + /* LineTable */ + /* LineHighlight */ + /* LineNumbersTable */ + /* LineNumbers */ + /* Line */ + /* Keyword */ + /* KeywordConstant */ + /* KeywordDeclaration */ + /* KeywordNamespace */ + /* KeywordPseudo */ + /* KeywordReserved */ + /* KeywordType */ + /* Name */ + /* NameAttribute */ + /* NameBuiltin */ + /* NameBuiltinPseudo */ + /* NameClass */ + /* NameConstant */ + /* NameDecorator */ + /* NameEntity */ + /* NameException */ + /* NameFunction */ + /* NameFunctionMagic */ + /* NameLabel */ + /* NameNamespace */ + /* NameOther */ + /* NameProperty */ + /* NameTag */ + /* NameVariable */ + /* NameVariableClass */ + /* NameVariableGlobal */ + /* NameVariableInstance */ + /* NameVariableMagic */ + /* Literal */ + /* LiteralDate */ + /* LiteralString */ + /* LiteralStringAffix */ + /* LiteralStringBacktick */ + /* LiteralStringChar */ + /* LiteralStringDelimiter */ + /* LiteralStringDoc */ + /* LiteralStringDouble */ + /* LiteralStringEscape */ + /* LiteralStringHeredoc */ + /* LiteralStringInterpol */ + /* LiteralStringOther */ + /* LiteralStringRegex */ + /* LiteralStringSingle */ + /* LiteralStringSymbol */ + /* LiteralNumber */ + /* LiteralNumberBin */ + /* LiteralNumberFloat */ + /* LiteralNumberHex */ + /* LiteralNumberInteger */ + /* LiteralNumberIntegerLong */ + /* LiteralNumberOct */ + /* Operator */ + /* OperatorWord */ + /* Punctuation */ + /* Comment */ + /* CommentHashbang */ + /* CommentMultiline */ + /* CommentSingle */ + /* CommentSpecial */ + /* CommentPreproc */ + /* CommentPreprocFile */ + /* Generic */ + /* GenericDeleted */ + /* GenericEmph */ + /* GenericError */ + /* GenericHeading */ + /* GenericInserted */ + /* GenericOutput */ + /* GenericPrompt */ + /* GenericStrong */ + /* GenericSubheading */ + /* GenericTraceback */ + /* GenericUnderline */ + /* TextWhitespace */ } + body.colorscheme-dark .bg { + color: #c9d1d9; + background-color: #0d1117; } + body.colorscheme-dark .chroma { + color: #c9d1d9; + background-color: #0d1117; } + body.colorscheme-dark .chroma .err { + color: #f85149; } + body.colorscheme-dark .chroma .lnlinks { + outline: none; + text-decoration: none; + color: inherit; } + body.colorscheme-dark .chroma .lntd { + vertical-align: top; + padding: 0; + margin: 0; + border: 0; } + body.colorscheme-dark .chroma .lntable { + border-spacing: 0; + padding: 0; + margin: 0; + border: 0; } + body.colorscheme-dark .chroma .hl { + background-color: #ffffcc; } + body.colorscheme-dark .chroma .lnt { + white-space: pre; + user-select: none; + margin-right: 0.4em; + padding: 0 0.4em 0 0.4em; + color: #64686c; } + body.colorscheme-dark .chroma .ln { + white-space: pre; + user-select: none; + margin-right: 0.4em; + padding: 0 0.4em 0 0.4em; + color: #6e7681; } + body.colorscheme-dark .chroma .line { + display: flex; } + body.colorscheme-dark .chroma .k { + color: #ff7b72; } + body.colorscheme-dark .chroma .kc { + color: #79c0ff; } + body.colorscheme-dark .chroma .kd { + color: #ff7b72; } + body.colorscheme-dark .chroma .kn { + color: #ff7b72; } + body.colorscheme-dark .chroma .kp { + color: #79c0ff; } + body.colorscheme-dark .chroma .kr { + color: #ff7b72; } + body.colorscheme-dark .chroma .kt { + color: #ff7b72; } + body.colorscheme-dark .chroma .nc { + color: #f0883e; + font-weight: bold; } + body.colorscheme-dark .chroma .no { + color: #79c0ff; + font-weight: bold; } + body.colorscheme-dark .chroma .nd { + color: #d2a8ff; + font-weight: bold; } + body.colorscheme-dark .chroma .ni { + color: #ffa657; } + body.colorscheme-dark .chroma .ne { + color: #f0883e; + font-weight: bold; } + body.colorscheme-dark .chroma .nf { + color: #d2a8ff; + font-weight: bold; } + body.colorscheme-dark .chroma .nl { + color: #79c0ff; + font-weight: bold; } + body.colorscheme-dark .chroma .nn { + color: #ff7b72; } + body.colorscheme-dark .chroma .py { + color: #79c0ff; } + body.colorscheme-dark .chroma .nt { + color: #7ee787; } + body.colorscheme-dark .chroma .nv { + color: #79c0ff; } + body.colorscheme-dark .chroma .l { + color: #a5d6ff; } + body.colorscheme-dark .chroma .ld { + color: #79c0ff; } + body.colorscheme-dark .chroma .s { + color: #a5d6ff; } + body.colorscheme-dark .chroma .sa { + color: #79c0ff; } + body.colorscheme-dark .chroma .sb { + color: #a5d6ff; } + body.colorscheme-dark .chroma .sc { + color: #a5d6ff; } + body.colorscheme-dark .chroma .dl { + color: #79c0ff; } + body.colorscheme-dark .chroma .sd { + color: #a5d6ff; } + body.colorscheme-dark .chroma .s2 { + color: #a5d6ff; } + body.colorscheme-dark .chroma .se { + color: #79c0ff; } + body.colorscheme-dark .chroma .sh { + color: #79c0ff; } + body.colorscheme-dark .chroma .si { + color: #a5d6ff; } + body.colorscheme-dark .chroma .sx { + color: #a5d6ff; } + body.colorscheme-dark .chroma .sr { + color: #79c0ff; } + body.colorscheme-dark .chroma .s1 { + color: #a5d6ff; } + body.colorscheme-dark .chroma .ss { + color: #a5d6ff; } + body.colorscheme-dark .chroma .m { + color: #a5d6ff; } + body.colorscheme-dark .chroma .mb { + color: #a5d6ff; } + body.colorscheme-dark .chroma .mf { + color: #a5d6ff; } + body.colorscheme-dark .chroma .mh { + color: #a5d6ff; } + body.colorscheme-dark .chroma .mi { + color: #a5d6ff; } + body.colorscheme-dark .chroma .il { + color: #a5d6ff; } + body.colorscheme-dark .chroma .mo { + color: #a5d6ff; } + body.colorscheme-dark .chroma .o { + color: #ff7b72; + font-weight: bold; } + body.colorscheme-dark .chroma .ow { + color: #ff7b72; + font-weight: bold; } + body.colorscheme-dark .chroma .c { + color: #8b949e; + font-style: italic; } + body.colorscheme-dark .chroma .ch { + color: #8b949e; + font-style: italic; } + body.colorscheme-dark .chroma .cm { + color: #8b949e; + font-style: italic; } + body.colorscheme-dark .chroma .c1 { + color: #8b949e; + font-style: italic; } + body.colorscheme-dark .chroma .cs { + color: #8b949e; + font-weight: bold; + font-style: italic; } + body.colorscheme-dark .chroma .cp { + color: #8b949e; + font-weight: bold; + font-style: italic; } + body.colorscheme-dark .chroma .cpf { + color: #8b949e; + font-weight: bold; + font-style: italic; } + body.colorscheme-dark .chroma .gd { + color: #ffa198; + background-color: #490202; } + body.colorscheme-dark .chroma .ge { + font-style: italic; } + body.colorscheme-dark .chroma .gr { + color: #ffa198; } + body.colorscheme-dark .chroma .gh { + color: #79c0ff; + font-weight: bold; } + body.colorscheme-dark .chroma .gi { + color: #56d364; + background-color: #0f5323; } + body.colorscheme-dark .chroma .go { + color: #8b949e; } + body.colorscheme-dark .chroma .gp { + color: #8b949e; } + body.colorscheme-dark .chroma .gs { + font-weight: bold; } + body.colorscheme-dark .chroma .gu { + color: #79c0ff; } + body.colorscheme-dark .chroma .gt { + color: #ff7b72; } + body.colorscheme-dark .chroma .gl { + text-decoration: underline; } + body.colorscheme-dark .chroma .w { + color: #6e7681; } + +@media (prefers-color-scheme: dark) { + body.colorscheme-auto { + /* Background */ + /* PreWrapper */ + /* Other */ + /* Error */ + /* CodeLine */ + /* LineLink */ + /* LineTableTD */ + /* LineTable */ + /* LineHighlight */ + /* LineNumbersTable */ + /* LineNumbers */ + /* Line */ + /* Keyword */ + /* KeywordConstant */ + /* KeywordDeclaration */ + /* KeywordNamespace */ + /* KeywordPseudo */ + /* KeywordReserved */ + /* KeywordType */ + /* Name */ + /* NameAttribute */ + /* NameBuiltin */ + /* NameBuiltinPseudo */ + /* NameClass */ + /* NameConstant */ + /* NameDecorator */ + /* NameEntity */ + /* NameException */ + /* NameFunction */ + /* NameFunctionMagic */ + /* NameLabel */ + /* NameNamespace */ + /* NameOther */ + /* NameProperty */ + /* NameTag */ + /* NameVariable */ + /* NameVariableClass */ + /* NameVariableGlobal */ + /* NameVariableInstance */ + /* NameVariableMagic */ + /* Literal */ + /* LiteralDate */ + /* LiteralString */ + /* LiteralStringAffix */ + /* LiteralStringBacktick */ + /* LiteralStringChar */ + /* LiteralStringDelimiter */ + /* LiteralStringDoc */ + /* LiteralStringDouble */ + /* LiteralStringEscape */ + /* LiteralStringHeredoc */ + /* LiteralStringInterpol */ + /* LiteralStringOther */ + /* LiteralStringRegex */ + /* LiteralStringSingle */ + /* LiteralStringSymbol */ + /* LiteralNumber */ + /* LiteralNumberBin */ + /* LiteralNumberFloat */ + /* LiteralNumberHex */ + /* LiteralNumberInteger */ + /* LiteralNumberIntegerLong */ + /* LiteralNumberOct */ + /* Operator */ + /* OperatorWord */ + /* Punctuation */ + /* Comment */ + /* CommentHashbang */ + /* CommentMultiline */ + /* CommentSingle */ + /* CommentSpecial */ + /* CommentPreproc */ + /* CommentPreprocFile */ + /* Generic */ + /* GenericDeleted */ + /* GenericEmph */ + /* GenericError */ + /* GenericHeading */ + /* GenericInserted */ + /* GenericOutput */ + /* GenericPrompt */ + /* GenericStrong */ + /* GenericSubheading */ + /* GenericTraceback */ + /* GenericUnderline */ + /* TextWhitespace */ } + body.colorscheme-auto .bg { + color: #c9d1d9; + background-color: #0d1117; } + body.colorscheme-auto .chroma { + color: #c9d1d9; + background-color: #0d1117; } + body.colorscheme-auto .chroma .err { + color: #f85149; } + body.colorscheme-auto .chroma .lnlinks { + outline: none; + text-decoration: none; + color: inherit; } + body.colorscheme-auto .chroma .lntd { + vertical-align: top; + padding: 0; + margin: 0; + border: 0; } + body.colorscheme-auto .chroma .lntable { + border-spacing: 0; + padding: 0; + margin: 0; + border: 0; } + body.colorscheme-auto .chroma .hl { + background-color: #ffffcc; } + body.colorscheme-auto .chroma .lnt { + white-space: pre; + user-select: none; + margin-right: 0.4em; + padding: 0 0.4em 0 0.4em; + color: #64686c; } + body.colorscheme-auto .chroma .ln { + white-space: pre; + user-select: none; + margin-right: 0.4em; + padding: 0 0.4em 0 0.4em; + color: #6e7681; } + body.colorscheme-auto .chroma .line { + display: flex; } + body.colorscheme-auto .chroma .k { + color: #ff7b72; } + body.colorscheme-auto .chroma .kc { + color: #79c0ff; } + body.colorscheme-auto .chroma .kd { + color: #ff7b72; } + body.colorscheme-auto .chroma .kn { + color: #ff7b72; } + body.colorscheme-auto .chroma .kp { + color: #79c0ff; } + body.colorscheme-auto .chroma .kr { + color: #ff7b72; } + body.colorscheme-auto .chroma .kt { + color: #ff7b72; } + body.colorscheme-auto .chroma .nc { + color: #f0883e; + font-weight: bold; } + body.colorscheme-auto .chroma .no { + color: #79c0ff; + font-weight: bold; } + body.colorscheme-auto .chroma .nd { + color: #d2a8ff; + font-weight: bold; } + body.colorscheme-auto .chroma .ni { + color: #ffa657; } + body.colorscheme-auto .chroma .ne { + color: #f0883e; + font-weight: bold; } + body.colorscheme-auto .chroma .nf { + color: #d2a8ff; + font-weight: bold; } + body.colorscheme-auto .chroma .nl { + color: #79c0ff; + font-weight: bold; } + body.colorscheme-auto .chroma .nn { + color: #ff7b72; } + body.colorscheme-auto .chroma .py { + color: #79c0ff; } + body.colorscheme-auto .chroma .nt { + color: #7ee787; } + body.colorscheme-auto .chroma .nv { + color: #79c0ff; } + body.colorscheme-auto .chroma .l { + color: #a5d6ff; } + body.colorscheme-auto .chroma .ld { + color: #79c0ff; } + body.colorscheme-auto .chroma .s { + color: #a5d6ff; } + body.colorscheme-auto .chroma .sa { + color: #79c0ff; } + body.colorscheme-auto .chroma .sb { + color: #a5d6ff; } + body.colorscheme-auto .chroma .sc { + color: #a5d6ff; } + body.colorscheme-auto .chroma .dl { + color: #79c0ff; } + body.colorscheme-auto .chroma .sd { + color: #a5d6ff; } + body.colorscheme-auto .chroma .s2 { + color: #a5d6ff; } + body.colorscheme-auto .chroma .se { + color: #79c0ff; } + body.colorscheme-auto .chroma .sh { + color: #79c0ff; } + body.colorscheme-auto .chroma .si { + color: #a5d6ff; } + body.colorscheme-auto .chroma .sx { + color: #a5d6ff; } + body.colorscheme-auto .chroma .sr { + color: #79c0ff; } + body.colorscheme-auto .chroma .s1 { + color: #a5d6ff; } + body.colorscheme-auto .chroma .ss { + color: #a5d6ff; } + body.colorscheme-auto .chroma .m { + color: #a5d6ff; } + body.colorscheme-auto .chroma .mb { + color: #a5d6ff; } + body.colorscheme-auto .chroma .mf { + color: #a5d6ff; } + body.colorscheme-auto .chroma .mh { + color: #a5d6ff; } + body.colorscheme-auto .chroma .mi { + color: #a5d6ff; } + body.colorscheme-auto .chroma .il { + color: #a5d6ff; } + body.colorscheme-auto .chroma .mo { + color: #a5d6ff; } + body.colorscheme-auto .chroma .o { + color: #ff7b72; + font-weight: bold; } + body.colorscheme-auto .chroma .ow { + color: #ff7b72; + font-weight: bold; } + body.colorscheme-auto .chroma .c { + color: #8b949e; + font-style: italic; } + body.colorscheme-auto .chroma .ch { + color: #8b949e; + font-style: italic; } + body.colorscheme-auto .chroma .cm { + color: #8b949e; + font-style: italic; } + body.colorscheme-auto .chroma .c1 { + color: #8b949e; + font-style: italic; } + body.colorscheme-auto .chroma .cs { + color: #8b949e; + font-weight: bold; + font-style: italic; } + body.colorscheme-auto .chroma .cp { + color: #8b949e; + font-weight: bold; + font-style: italic; } + body.colorscheme-auto .chroma .cpf { + color: #8b949e; + font-weight: bold; + font-style: italic; } + body.colorscheme-auto .chroma .gd { + color: #ffa198; + background-color: #490202; } + body.colorscheme-auto .chroma .ge { + font-style: italic; } + body.colorscheme-auto .chroma .gr { + color: #ffa198; } + body.colorscheme-auto .chroma .gh { + color: #79c0ff; + font-weight: bold; } + body.colorscheme-auto .chroma .gi { + color: #56d364; + background-color: #0f5323; } + body.colorscheme-auto .chroma .go { + color: #8b949e; } + body.colorscheme-auto .chroma .gp { + color: #8b949e; } + body.colorscheme-auto .chroma .gs { + font-weight: bold; } + body.colorscheme-auto .chroma .gu { + color: #79c0ff; } + body.colorscheme-auto .chroma .gt { + color: #ff7b72; } + body.colorscheme-auto .chroma .gl { + text-decoration: underline; } + body.colorscheme-auto .chroma .w { + color: #6e7681; } } + +/*# sourceMappingURL=coder-dark.css.map */ \ No newline at end of file diff --git a/public/css/coder-dark.css.map b/public/css/coder-dark.css.map new file mode 100644 index 00000000..e90be719 --- /dev/null +++ b/public/css/coder-dark.css.map @@ -0,0 +1,33 @@ +{ + "version": 3, + "file": "coder-dark.css", + "sourceRoot": "/Users/Ryan.Nemeth/repos/rnemeth90.github.io", + "sources": [ + "themes/hugo-coder/assets/scss/coder-dark.scss", + "themes/hugo-coder/assets/scss/_variables.scss", + "themes/hugo-coder/assets/scss/_base_dark.scss", + "themes/hugo-coder/assets/scss/_content_dark.scss", + "themes/hugo-coder/assets/scss/_notices_dark.scss", + "themes/hugo-coder/assets/scss/_navigation_dark.scss", + "themes/hugo-coder/assets/scss/_tabs_dark.scss", + "themes/hugo-coder/assets/scss/_taxonomies_dark.scss", + "themes/hugo-coder/assets/scss/_footer_dark.scss", + "themes/hugo-coder/assets/scss/_float_dark.scss", + "themes/hugo-coder/assets/scss/_syntax_dark.scss" + ], + "sourcesContent": [ + "@import \"variables\";\n@import \"base_dark\";\n@import \"content_dark\";\n@import \"notices_dark\";\n@import \"navigation_dark\";\n@import \"tabs_dark\";\n@import \"taxonomies_dark\";\n@import \"footer_dark\";\n@import \"float_dark\";\n@import \"syntax_dark\";\n", + "// Fonts\n$font-family: -apple-system,\nBlinkMacSystemFont,\n\"Segoe UI\",\nRoboto,\nOxygen-Sans,\nUbuntu,\nCantarell,\n\"Helvetica Neue\",\nHelvetica,\n\"游ゴシック\",\n\"PingFang SC\",\nSTXihei,\"华文细黑\",\n\"Microsoft YaHei\",\"微软雅黑\",\nSimSun,\"宋体\",\nHeiti,\"黑体\",\nsans-serif;\n$code-font-family: SFMono-Regular,\nConsolas,\nLiberation Mono,\nMenlo,\nmonospace;\n\n// Colors\n$bg-color: #fafafa !default;\n$fg-color: #212121 !default;\n$alt-bg-color: #e0e0e0 !default;\n$alt-fg-color: #000 !default;\n$darker-alt-bg-color: #ccc !default;\n$link-color: #1565c0 !default;\n\n// Dark colors\n$bg-color-dark: #212121 !default;\n$fg-color-dark: #dadada !default;\n$alt-bg-color-dark: #424242 !default;\n$alt-fg-color-dark: #dadada !default;\n$lighter-alt-bg-color-dark: #4f4f4f !default;\n$link-color-dark: #42a5f5 !default;\n\n// Notice colors\n$fg-color-notice-note-icon: #5e35b1 !default;\n$bg-color-notice-note-title: #673ab71a !default;\n$bg-color-notice-note-content: #7e57c21a !default;\n$fg-color-notice-tip-icon: #00897b !default;\n$bg-color-notice-tip-title: #0096881a !default;\n$bg-color-notice-tip-content: #26a69a1a !default;\n$fg-color-notice-example-icon: #6d4c41 !default;\n$bg-color-notice-example-title: #7955481a !default;\n$bg-color-notice-example-content: #8d6e631a !default;\n$fg-color-notice-question-icon: #7cb342 !default;\n$bg-color-notice-question-title: #8bc34a1a !default;\n$bg-color-notice-question-content: #9ccc651a !default;\n$fg-color-notice-info-icon: #1e88e5 !default;\n$bg-color-notice-info-title: #2196f31a !default;\n$bg-color-notice-info-content: #42a5f51a !default;\n$fg-color-notice-warning-icon: #ffb300 !default;\n$bg-color-notice-warning-title: #ffc1071a !default;\n$bg-color-notice-warning-content: #ffca281a !default;\n$fg-color-notice-error-icon: #e53935 !default;\n$bg-color-notice-error-title: #f443361a !default;\n$bg-color-notice-error-content: #ef53501a !default;\n\n// Path to FontAwesome TTF/WOFF files.\n$fa-font-path: \"../fonts\" !default;\n", + "@mixin base_dark {\n color: $fg-color-dark;\n background-color: $bg-color-dark;\n\n a {\n color: $link-color-dark;\n }\n\n h1,\n h2,\n h3,\n h4,\n h5,\n h6 {\n color: $alt-fg-color-dark;\n\n &:hover .heading-link {\n visibility: visible;\n }\n\n .heading-link {\n color: $link-color-dark;\n font-weight: inherit;\n text-decoration: none;\n font-size: 80%;\n visibility: hidden;\n }\n\n .title-link {\n color: inherit;\n font-weight: inherit;\n text-decoration: none;\n }\n }\n\n pre code {\n background-color: inherit;\n color: inherit;\n }\n\n code {\n background-color: $lighter-alt-bg-color-dark;\n color: $fg-color-dark;\n }\n\n blockquote {\n border-left: 2px solid $alt-bg-color-dark;\n }\n\n th,\n td {\n padding: 1.6rem;\n }\n\n table {\n border-collapse: collapse;\n }\n\n table td,\n table th {\n border: 2px solid $alt-fg-color-dark;\n }\n\n table tr:first-child th {\n border-top: 0;\n }\n\n table tr:last-child td {\n border-bottom: 0;\n }\n\n table tr td:first-child,\n table tr th:first-child {\n border-left: 0;\n }\n\n table tr td:last-child,\n table tr th:last-child {\n border-right: 0;\n }\n}\n\nbody.colorscheme-dark {\n @include base_dark();\n}\n\nbody.colorscheme-auto {\n @media (prefers-color-scheme: dark) {\n @include base_dark();\n }\n}\n", + "@mixin content_dark {\n .content {\n .post {\n .tags {\n .tag {\n background-color: $alt-bg-color-dark;\n\n a {\n color: $fg-color-dark;\n }\n a:active {\n color: $fg-color-dark;\n }\n }\n }\n }\n .list {\n ul {\n li {\n .title {\n color: $fg-color-dark;\n\n &:hover,\n &:focus {\n color: $link-color-dark;\n }\n }\n }\n }\n }\n\n .centered {\n .about {\n ul {\n li {\n a {\n color: $fg-color-dark;\n\n &:hover,\n &:focus {\n color: $link-color-dark;\n }\n }\n }\n }\n }\n }\n }\n}\n\nbody.colorscheme-dark {\n @include content_dark();\n}\n\nbody.colorscheme-auto {\n @media (prefers-color-scheme: dark) {\n @include content_dark();\n }\n}\n", + "@mixin notices_dark {\n .notice {\n .notice-title {\n border-bottom: 1px solid $bg-color-dark;\n }\n }\n}\n\nbody.colorscheme-dark {\n @include notices_dark();\n}\n\nbody.colorscheme-auto {\n @media (prefers-color-scheme: dark) {\n @include notices_dark();\n }\n}\n", + "@mixin navigation_dark {\n .navigation {\n\n a,\n span {\n color: $fg-color-dark;\n }\n\n a {\n\n &:hover,\n &:focus {\n color: $link-color-dark;\n }\n }\n\n .navigation-list {\n @media only screen and (max-width: 768px) {\n background-color: $bg-color-dark;\n border-top: solid 2px $alt-bg-color-dark;\n border-bottom: solid 2px $alt-bg-color-dark;\n }\n\n .menu-separator {\n @media only screen and (max-width: 768px) {\n border-top: 2px solid $fg-color-dark;\n }\n }\n }\n\n #menu-toggle {\n @media only screen and (max-width: 768px) {\n &:checked+label>i {\n color: $alt-bg-color-dark;\n }\n }\n }\n\n i {\n color: $fg-color-dark;\n\n &:hover,\n &:focus {\n color: $link-color-dark;\n }\n }\n\n .menu-button {\n i {\n\n &:hover,\n &:focus {\n color: $alt-fg-color-dark;\n }\n }\n }\n }\n}\n\nbody.colorscheme-dark {\n @include navigation_dark();\n}\n\nbody.colorscheme-auto {\n @media (prefers-color-scheme: dark) {\n @include navigation_dark();\n }\n}\n", + "@mixin tabs_dark {\n .tabs {\n label.tab-label {\n background-color: $alt-bg-color-dark;\n border-color: $lighter-alt-bg-color-dark;\n }\n\n input.tab-input:checked + label.tab-label {\n background-color: $bg-color-dark;\n }\n\n .tab-content {\n background-color: $bg-color-dark;\n border-color: $lighter-alt-bg-color-dark;\n }\n }\n}\n\nbody.colorscheme-dark {\n @include tabs_dark();\n}\n\nbody.colorscheme-auto {\n @media (prefers-color-scheme: dark) {\n @include tabs_dark();\n }\n}\n", + "@mixin taxonomy_dark {\n .taxonomy-element {\n background-color: $alt-bg-color-dark;\n\n a {\n color: $fg-color-dark;\n }\n a:active {\n color: $fg-color-dark;\n }\n }\n}\n\nbody.colorscheme-dark {\n @include taxonomy_dark();\n}\n\nbody.colorscheme-auto {\n @media (prefers-color-scheme: dark) {\n @include taxonomy_dark();\n }\n}\n", + "@mixin footer_dark {\n .footer {\n a {\n color: $link-color-dark;\n }\n }\n}\n\nbody.colorscheme-dark {\n @include footer_dark();\n}\n\nbody.colorscheme-auto {\n @media (prefers-color-scheme: dark) {\n @include footer_dark();\n }\n}\n", + "@mixin float_dark {\n .float-container {\n a {\n color: $alt-fg-color-dark;\n background-color: $alt-bg-color-dark;\n\n &:hover,\n &:focus {\n color: $link-color-dark;\n\n @media only screen and (max-width: 768px) {\n color: $alt-fg-color-dark;\n }\n }\n }\n }\n}\n\nbody.colorscheme-dark {\n @include float_dark();\n}\n\nbody.colorscheme-auto {\n @media (prefers-color-scheme: dark) {\n @include float_dark();\n }\n}\n", + "@mixin syntax_dark {\n /* Background */ .bg { color: #c9d1d9; background-color: #0d1117; }\n /* PreWrapper */ .chroma { color: #c9d1d9; background-color: #0d1117; }\n /* Other */ .chroma .x { }\n /* Error */ .chroma .err { color: #f85149 }\n /* CodeLine */ .chroma .cl { }\n /* LineLink */ .chroma .lnlinks { outline: none; text-decoration: none; color: inherit }\n /* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }\n /* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; }\n /* LineHighlight */ .chroma .hl { background-color: #ffffcc }\n /* LineNumbersTable */ .chroma .lnt { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #64686c }\n /* LineNumbers */ .chroma .ln { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #6e7681 }\n /* Line */ .chroma .line { display: flex; }\n /* Keyword */ .chroma .k { color: #ff7b72 }\n /* KeywordConstant */ .chroma .kc { color: #79c0ff }\n /* KeywordDeclaration */ .chroma .kd { color: #ff7b72 }\n /* KeywordNamespace */ .chroma .kn { color: #ff7b72 }\n /* KeywordPseudo */ .chroma .kp { color: #79c0ff }\n /* KeywordReserved */ .chroma .kr { color: #ff7b72 }\n /* KeywordType */ .chroma .kt { color: #ff7b72 }\n /* Name */ .chroma .n { }\n /* NameAttribute */ .chroma .na { }\n /* NameBuiltin */ .chroma .nb { }\n /* NameBuiltinPseudo */ .chroma .bp { }\n /* NameClass */ .chroma .nc { color: #f0883e; font-weight: bold }\n /* NameConstant */ .chroma .no { color: #79c0ff; font-weight: bold }\n /* NameDecorator */ .chroma .nd { color: #d2a8ff; font-weight: bold }\n /* NameEntity */ .chroma .ni { color: #ffa657 }\n /* NameException */ .chroma .ne { color: #f0883e; font-weight: bold }\n /* NameFunction */ .chroma .nf { color: #d2a8ff; font-weight: bold }\n /* NameFunctionMagic */ .chroma .fm { }\n /* NameLabel */ .chroma .nl { color: #79c0ff; font-weight: bold }\n /* NameNamespace */ .chroma .nn { color: #ff7b72 }\n /* NameOther */ .chroma .nx { }\n /* NameProperty */ .chroma .py { color: #79c0ff }\n /* NameTag */ .chroma .nt { color: #7ee787 }\n /* NameVariable */ .chroma .nv { color: #79c0ff }\n /* NameVariableClass */ .chroma .vc { }\n /* NameVariableGlobal */ .chroma .vg { }\n /* NameVariableInstance */ .chroma .vi { }\n /* NameVariableMagic */ .chroma .vm { }\n /* Literal */ .chroma .l { color: #a5d6ff }\n /* LiteralDate */ .chroma .ld { color: #79c0ff }\n /* LiteralString */ .chroma .s { color: #a5d6ff }\n /* LiteralStringAffix */ .chroma .sa { color: #79c0ff }\n /* LiteralStringBacktick */ .chroma .sb { color: #a5d6ff }\n /* LiteralStringChar */ .chroma .sc { color: #a5d6ff }\n /* LiteralStringDelimiter */ .chroma .dl { color: #79c0ff }\n /* LiteralStringDoc */ .chroma .sd { color: #a5d6ff }\n /* LiteralStringDouble */ .chroma .s2 { color: #a5d6ff }\n /* LiteralStringEscape */ .chroma .se { color: #79c0ff }\n /* LiteralStringHeredoc */ .chroma .sh { color: #79c0ff }\n /* LiteralStringInterpol */ .chroma .si { color: #a5d6ff }\n /* LiteralStringOther */ .chroma .sx { color: #a5d6ff }\n /* LiteralStringRegex */ .chroma .sr { color: #79c0ff }\n /* LiteralStringSingle */ .chroma .s1 { color: #a5d6ff }\n /* LiteralStringSymbol */ .chroma .ss { color: #a5d6ff }\n /* LiteralNumber */ .chroma .m { color: #a5d6ff }\n /* LiteralNumberBin */ .chroma .mb { color: #a5d6ff }\n /* LiteralNumberFloat */ .chroma .mf { color: #a5d6ff }\n /* LiteralNumberHex */ .chroma .mh { color: #a5d6ff }\n /* LiteralNumberInteger */ .chroma .mi { color: #a5d6ff }\n /* LiteralNumberIntegerLong */ .chroma .il { color: #a5d6ff }\n /* LiteralNumberOct */ .chroma .mo { color: #a5d6ff }\n /* Operator */ .chroma .o { color: #ff7b72; font-weight: bold }\n /* OperatorWord */ .chroma .ow { color: #ff7b72; font-weight: bold }\n /* Punctuation */ .chroma .p { }\n /* Comment */ .chroma .c { color: #8b949e; font-style: italic }\n /* CommentHashbang */ .chroma .ch { color: #8b949e; font-style: italic }\n /* CommentMultiline */ .chroma .cm { color: #8b949e; font-style: italic }\n /* CommentSingle */ .chroma .c1 { color: #8b949e; font-style: italic }\n /* CommentSpecial */ .chroma .cs { color: #8b949e; font-weight: bold; font-style: italic }\n /* CommentPreproc */ .chroma .cp { color: #8b949e; font-weight: bold; font-style: italic }\n /* CommentPreprocFile */ .chroma .cpf { color: #8b949e; font-weight: bold; font-style: italic }\n /* Generic */ .chroma .g { }\n /* GenericDeleted */ .chroma .gd { color: #ffa198; background-color: #490202 }\n /* GenericEmph */ .chroma .ge { font-style: italic }\n /* GenericError */ .chroma .gr { color: #ffa198 }\n /* GenericHeading */ .chroma .gh { color: #79c0ff; font-weight: bold }\n /* GenericInserted */ .chroma .gi { color: #56d364; background-color: #0f5323 }\n /* GenericOutput */ .chroma .go { color: #8b949e }\n /* GenericPrompt */ .chroma .gp { color: #8b949e }\n /* GenericStrong */ .chroma .gs { font-weight: bold }\n /* GenericSubheading */ .chroma .gu { color: #79c0ff }\n /* GenericTraceback */ .chroma .gt { color: #ff7b72 }\n /* GenericUnderline */ .chroma .gl { text-decoration: underline }\n /* TextWhitespace */ .chroma .w { color: #6e7681 }\n}\n\nbody.colorscheme-dark {\n @include syntax_dark();\n}\n\nbody.colorscheme-auto {\n @media (prefers-color-scheme: dark) {\n @include syntax_dark();\n }\n}\n" + ], + "names": [], + "mappings": "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" +} \ No newline at end of file diff --git a/public/css/coder.css b/public/css/coder.css new file mode 100644 index 00000000..8c3ae8d1 --- /dev/null +++ b/public/css/coder.css @@ -0,0 +1,13462 @@ +@charset "UTF-8"; +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ +/* Document + ========================================================================== */ +/** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in iOS. + */ +html { + line-height: 1.15; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ } + +/* Sections + ========================================================================== */ +/** + * Remove the margin in all browsers. + */ +body { + margin: 0; } + +/** + * Render the `main` element consistently in IE. + */ +main { + display: block; } + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ +h1 { + font-size: 2em; + margin: 0.67em 0; } + +/* Grouping content + ========================================================================== */ +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ +hr { + box-sizing: content-box; + /* 1 */ + height: 0; + /* 1 */ + overflow: visible; + /* 2 */ } + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ +pre { + font-family: monospace, monospace; + /* 1 */ + font-size: 1em; + /* 2 */ } + +/* Text-level semantics + ========================================================================== */ +/** + * Remove the gray background on active links in IE 10. + */ +a { + background-color: transparent; + word-wrap: break-word; } + +/** + * 1. Remove the bottom border in Chrome 57- + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ +abbr[title] { + border-bottom: none; + /* 1 */ + text-decoration: underline; + /* 2 */ + text-decoration: underline dotted; + /* 2 */ } + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ +b, +strong { + font-weight: bolder; } + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ +code, +kbd, +samp { + font-family: monospace, monospace; + /* 1 */ + font-size: 1em; + /* 2 */ } + +/** + * Add the correct font size in all browsers. + */ +small { + font-size: 80%; } + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; } + +sub { + bottom: -0.25em; } + +sup { + top: -0.5em; } + +/* Embedded content + ========================================================================== */ +/** + * Remove the border on images inside links in IE 10. + */ +img { + border-style: none; } + +/* Forms + ========================================================================== */ +/** + * 1. Change the font styles in all browsers. + * 2. Remove the margin in Firefox and Safari. + */ +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + line-height: 1.15; + /* 1 */ + margin: 0; + /* 2 */ } + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ +button, +input { + /* 1 */ + overflow: visible; } + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ +button, +select { + /* 1 */ + text-transform: none; } + +/** + * Correct the inability to style clickable types in iOS and Safari. + */ +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; } + +/** + * Remove the inner border and padding in Firefox. + */ +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; } + +/** + * Restore the focus styles unset by the previous rule. + */ +button:-moz-focusring, +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; } + +/** + * Correct the padding in Firefox. + */ +fieldset { + padding: 0.35em 0.75em 0.625em; } + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ +legend { + box-sizing: border-box; + /* 1 */ + color: inherit; + /* 2 */ + display: table; + /* 1 */ + max-width: 100%; + /* 1 */ + padding: 0; + /* 3 */ + white-space: normal; + /* 1 */ } + +/** + * Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ +progress { + vertical-align: baseline; } + +/** + * Remove the default vertical scrollbar in IE 10+. + */ +textarea { + overflow: auto; } + +/** + * 1. Add the correct box sizing in IE 10. + * 2. Remove the padding in IE 10. + */ +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; + /* 1 */ + padding: 0; + /* 2 */ } + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; } + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ +[type="search"] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ } + +/** + * Remove the inner padding in Chrome and Safari on macOS. + */ +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; } + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ +::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ } + +/* Interactive + ========================================================================== */ +/* + * Add the correct display in Edge, IE 10+, and Firefox. + */ +details { + display: block; } + +/* + * Add the correct display in all browsers. + */ +summary { + display: list-item; } + +/* Misc + ========================================================================== */ +/** + * Add the correct display in IE 10+. + */ +template { + display: none; } + +/** + * Add the correct display in IE 10. + */ +[hidden] { + display: none; } + +/*! + * Font Awesome Free 6.7.1 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +.fa { + font-family: var(--fa-style-family, "Font Awesome 6 Free"); + font-weight: var(--fa-style, 900); } + +.fas, +.far, +.fab, +.fa-solid, +.content article a:where(.external-link):not(:has(img)):after, +.fa-regular, +.fa-brands, +.fa { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: var(--fa-display, inline-block); + font-style: normal; + font-variant: normal; + line-height: 1; + text-rendering: auto; } + +.fas::before, +.far::before, +.fab::before, +.fa-solid::before, +.fa-regular::before, +.fa-brands::before, +.fa::before { + content: var(--fa); } + +.fa-classic, +.fas, +.fa-solid, +.content article a:where(.external-link):not(:has(img)):after, +.far, +.fa-regular { + font-family: 'Font Awesome 6 Free'; } + +.fa-brands, +.fab { + font-family: 'Font Awesome 6 Brands'; } + +.content article a:where(.external-link):not(:has(img)):after { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + display: inline-block; + font-style: normal; + font-variant: normal; + font-weight: normal; + line-height: 1; } + +.fa-1x { + font-size: 1em; } + +.fa-2x { + font-size: 2em; } + +.fa-3x { + font-size: 3em; } + +.fa-4x { + font-size: 4em; } + +.fa-5x { + font-size: 5em; } + +.fa-6x { + font-size: 6em; } + +.fa-7x { + font-size: 7em; } + +.fa-8x { + font-size: 8em; } + +.fa-9x { + font-size: 9em; } + +.fa-10x { + font-size: 10em; } + +.fa-2xs { + font-size: 0.625em; + line-height: 0.1em; + vertical-align: 0.225em; } + +.fa-xs { + font-size: 0.75em; + line-height: 0.08333333em; + vertical-align: 0.125em; } + +.fa-sm { + font-size: 0.875em; + line-height: 0.07142857em; + vertical-align: 0.05357143em; } + +.fa-lg { + font-size: 1.25em; + line-height: 0.05em; + vertical-align: -0.075em; } + +.fa-xl { + font-size: 1.5em; + line-height: 0.04166667em; + vertical-align: -0.125em; } + +.fa-2xl { + font-size: 2em; + line-height: 0.03125em; + vertical-align: -0.1875em; } + +.fa-fw { + text-align: center; + width: 1.25em; } + +.fa-ul { + list-style-type: none; + margin-left: var(--fa-li-margin, 2.5em); + padding-left: 0; } + .fa-ul > li { + position: relative; } + +.fa-li { + left: calc(-1 * var(--fa-li-width, 2em)); + position: absolute; + text-align: center; + width: var(--fa-li-width, 2em); + line-height: inherit; } + +.fa-border { + border-color: var(--fa-border-color, #eee); + border-radius: var(--fa-border-radius, 0.1em); + border-style: var(--fa-border-style, solid); + border-width: var(--fa-border-width, 0.08em); + padding: var(--fa-border-padding, 0.2em 0.25em 0.15em); } + +.fa-pull-left { + float: left; + margin-right: var(--fa-pull-margin, 0.3em); } + +.fa-pull-right { + float: right; + margin-left: var(--fa-pull-margin, 0.3em); } + +.fa-beat { + animation-name: fa-beat; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, ease-in-out); } + +.fa-bounce { + animation-name: fa-bounce; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); } + +.fa-fade { + animation-name: fa-fade; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); } + +.fa-beat-fade { + animation-name: fa-beat-fade; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); } + +.fa-flip { + animation-name: fa-flip; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, ease-in-out); } + +.fa-shake { + animation-name: fa-shake; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, linear); } + +.fa-spin { + animation-name: fa-spin; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 2s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, linear); } + +.fa-spin-reverse { + --fa-animation-direction: reverse; } + +.fa-pulse, +.fa-spin-pulse { + animation-name: fa-spin; + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, steps(8)); } + +@media (prefers-reduced-motion: reduce) { + .fa-beat, + .fa-bounce, + .fa-fade, + .fa-beat-fade, + .fa-flip, + .fa-pulse, + .fa-shake, + .fa-spin, + .fa-spin-pulse { + animation-delay: -1ms; + animation-duration: 1ms; + animation-iteration-count: 1; + transition-delay: 0s; + transition-duration: 0s; } } + +@keyframes fa-beat { + 0%, 90% { + transform: scale(1); } + 45% { + transform: scale(var(--fa-beat-scale, 1.25)); } } + +@keyframes fa-bounce { + 0% { + transform: scale(1, 1) translateY(0); } + 10% { + transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); } + 30% { + transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); } + 50% { + transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); } + 57% { + transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); } + 64% { + transform: scale(1, 1) translateY(0); } + 100% { + transform: scale(1, 1) translateY(0); } } + +@keyframes fa-fade { + 50% { + opacity: var(--fa-fade-opacity, 0.4); } } + +@keyframes fa-beat-fade { + 0%, 100% { + opacity: var(--fa-beat-fade-opacity, 0.4); + transform: scale(1); } + 50% { + opacity: 1; + transform: scale(var(--fa-beat-fade-scale, 1.125)); } } + +@keyframes fa-flip { + 50% { + transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); } } + +@keyframes fa-shake { + 0% { + transform: rotate(-15deg); } + 4% { + transform: rotate(15deg); } + 8%, 24% { + transform: rotate(-18deg); } + 12%, 28% { + transform: rotate(18deg); } + 16% { + transform: rotate(-22deg); } + 20% { + transform: rotate(22deg); } + 32% { + transform: rotate(-12deg); } + 36% { + transform: rotate(12deg); } + 40%, 100% { + transform: rotate(0deg); } } + +@keyframes fa-spin { + 0% { + transform: rotate(0deg); } + 100% { + transform: rotate(360deg); } } + +.fa-rotate-90 { + transform: rotate(90deg); } + +.fa-rotate-180 { + transform: rotate(180deg); } + +.fa-rotate-270 { + transform: rotate(270deg); } + +.fa-flip-horizontal { + transform: scale(-1, 1); } + +.fa-flip-vertical { + transform: scale(1, -1); } + +.fa-flip-both, +.fa-flip-horizontal.fa-flip-vertical { + transform: scale(-1, -1); } + +.fa-rotate-by { + transform: rotate(var(--fa-rotate-angle, 0)); } + +.fa-stack { + display: inline-block; + height: 2em; + line-height: 2em; + position: relative; + vertical-align: middle; + width: 2.5em; } + +.fa-stack-1x, +.fa-stack-2x { + left: 0; + position: absolute; + text-align: center; + width: 100%; + z-index: var(--fa-stack-z-index, auto); } + +.fa-stack-1x { + line-height: inherit; } + +.fa-stack-2x { + font-size: 2em; } + +.fa-inverse { + color: var(--fa-inverse, #fff); } + +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen +readers do not read off random characters that represent icons */ +.fa-0 { + --fa: "\30"; + --fa--fa: "\30\30"; } + +.fa-1 { + --fa: "\31"; + --fa--fa: "\31\31"; } + +.fa-2 { + --fa: "\32"; + --fa--fa: "\32\32"; } + +.fa-3 { + --fa: "\33"; + --fa--fa: "\33\33"; } + +.fa-4 { + --fa: "\34"; + --fa--fa: "\34\34"; } + +.fa-5 { + --fa: "\35"; + --fa--fa: "\35\35"; } + +.fa-6 { + --fa: "\36"; + --fa--fa: "\36\36"; } + +.fa-7 { + --fa: "\37"; + --fa--fa: "\37\37"; } + +.fa-8 { + --fa: "\38"; + --fa--fa: "\38\38"; } + +.fa-9 { + --fa: "\39"; + --fa--fa: "\39\39"; } + +.fa-fill-drip { + --fa: "\f576"; + --fa--fa: "\f576\f576"; } + +.fa-arrows-to-circle { + --fa: "\e4bd"; + --fa--fa: "\e4bd\e4bd"; } + +.fa-circle-chevron-right { + --fa: "\f138"; + --fa--fa: "\f138\f138"; } + +.fa-chevron-circle-right { + --fa: "\f138"; + --fa--fa: "\f138\f138"; } + +.fa-at { + --fa: "\40"; + --fa--fa: "\40\40"; } + +.fa-trash-can { + --fa: "\f2ed"; + --fa--fa: "\f2ed\f2ed"; } + +.fa-trash-alt { + --fa: "\f2ed"; + --fa--fa: "\f2ed\f2ed"; } + +.fa-text-height { + --fa: "\f034"; + --fa--fa: "\f034\f034"; } + +.fa-user-xmark { + --fa: "\f235"; + --fa--fa: "\f235\f235"; } + +.fa-user-times { + --fa: "\f235"; + --fa--fa: "\f235\f235"; } + +.fa-stethoscope { + --fa: "\f0f1"; + --fa--fa: "\f0f1\f0f1"; } + +.fa-message { + --fa: "\f27a"; + --fa--fa: "\f27a\f27a"; } + +.fa-comment-alt { + --fa: "\f27a"; + --fa--fa: "\f27a\f27a"; } + +.fa-info { + --fa: "\f129"; + --fa--fa: "\f129\f129"; } + +.fa-down-left-and-up-right-to-center { + --fa: "\f422"; + --fa--fa: "\f422\f422"; } + +.fa-compress-alt { + --fa: "\f422"; + --fa--fa: "\f422\f422"; } + +.fa-explosion { + --fa: "\e4e9"; + --fa--fa: "\e4e9\e4e9"; } + +.fa-file-lines { + --fa: "\f15c"; + --fa--fa: "\f15c\f15c"; } + +.fa-file-alt { + --fa: "\f15c"; + --fa--fa: "\f15c\f15c"; } + +.fa-file-text { + --fa: "\f15c"; + --fa--fa: "\f15c\f15c"; } + +.fa-wave-square { + --fa: "\f83e"; + --fa--fa: "\f83e\f83e"; } + +.fa-ring { + --fa: "\f70b"; + --fa--fa: "\f70b\f70b"; } + +.fa-building-un { + --fa: "\e4d9"; + --fa--fa: "\e4d9\e4d9"; } + +.fa-dice-three { + --fa: "\f527"; + --fa--fa: "\f527\f527"; } + +.fa-calendar-days { + --fa: "\f073"; + --fa--fa: "\f073\f073"; } + +.fa-calendar-alt { + --fa: "\f073"; + --fa--fa: "\f073\f073"; } + +.fa-anchor-circle-check { + --fa: "\e4aa"; + --fa--fa: "\e4aa\e4aa"; } + +.fa-building-circle-arrow-right { + --fa: "\e4d1"; + --fa--fa: "\e4d1\e4d1"; } + +.fa-volleyball { + --fa: "\f45f"; + --fa--fa: "\f45f\f45f"; } + +.fa-volleyball-ball { + --fa: "\f45f"; + --fa--fa: "\f45f\f45f"; } + +.fa-arrows-up-to-line { + --fa: "\e4c2"; + --fa--fa: "\e4c2\e4c2"; } + +.fa-sort-down { + --fa: "\f0dd"; + --fa--fa: "\f0dd\f0dd"; } + +.fa-sort-desc { + --fa: "\f0dd"; + --fa--fa: "\f0dd\f0dd"; } + +.fa-circle-minus { + --fa: "\f056"; + --fa--fa: "\f056\f056"; } + +.fa-minus-circle { + --fa: "\f056"; + --fa--fa: "\f056\f056"; } + +.fa-door-open { + --fa: "\f52b"; + --fa--fa: "\f52b\f52b"; } + +.fa-right-from-bracket { + --fa: "\f2f5"; + --fa--fa: "\f2f5\f2f5"; } + +.fa-sign-out-alt { + --fa: "\f2f5"; + --fa--fa: "\f2f5\f2f5"; } + +.fa-atom { + --fa: "\f5d2"; + --fa--fa: "\f5d2\f5d2"; } + +.fa-soap { + --fa: "\e06e"; + --fa--fa: "\e06e\e06e"; } + +.fa-icons { + --fa: "\f86d"; + --fa--fa: "\f86d\f86d"; } + +.fa-heart-music-camera-bolt { + --fa: "\f86d"; + --fa--fa: "\f86d\f86d"; } + +.fa-microphone-lines-slash { + --fa: "\f539"; + --fa--fa: "\f539\f539"; } + +.fa-microphone-alt-slash { + --fa: "\f539"; + --fa--fa: "\f539\f539"; } + +.fa-bridge-circle-check { + --fa: "\e4c9"; + --fa--fa: "\e4c9\e4c9"; } + +.fa-pump-medical { + --fa: "\e06a"; + --fa--fa: "\e06a\e06a"; } + +.fa-fingerprint { + --fa: "\f577"; + --fa--fa: "\f577\f577"; } + +.fa-hand-point-right { + --fa: "\f0a4"; + --fa--fa: "\f0a4\f0a4"; } + +.fa-magnifying-glass-location { + --fa: "\f689"; + --fa--fa: "\f689\f689"; } + +.fa-search-location { + --fa: "\f689"; + --fa--fa: "\f689\f689"; } + +.fa-forward-step { + --fa: "\f051"; + --fa--fa: "\f051\f051"; } + +.fa-step-forward { + --fa: "\f051"; + --fa--fa: "\f051\f051"; } + +.fa-face-smile-beam { + --fa: "\f5b8"; + --fa--fa: "\f5b8\f5b8"; } + +.fa-smile-beam { + --fa: "\f5b8"; + --fa--fa: "\f5b8\f5b8"; } + +.fa-flag-checkered { + --fa: "\f11e"; + --fa--fa: "\f11e\f11e"; } + +.fa-football { + --fa: "\f44e"; + --fa--fa: "\f44e\f44e"; } + +.fa-football-ball { + --fa: "\f44e"; + --fa--fa: "\f44e\f44e"; } + +.fa-school-circle-exclamation { + --fa: "\e56c"; + --fa--fa: "\e56c\e56c"; } + +.fa-crop { + --fa: "\f125"; + --fa--fa: "\f125\f125"; } + +.fa-angles-down { + --fa: "\f103"; + --fa--fa: "\f103\f103"; } + +.fa-angle-double-down { + --fa: "\f103"; + --fa--fa: "\f103\f103"; } + +.fa-users-rectangle { + --fa: "\e594"; + --fa--fa: "\e594\e594"; } + +.fa-people-roof { + --fa: "\e537"; + --fa--fa: "\e537\e537"; } + +.fa-people-line { + --fa: "\e534"; + --fa--fa: "\e534\e534"; } + +.fa-beer-mug-empty { + --fa: "\f0fc"; + --fa--fa: "\f0fc\f0fc"; } + +.fa-beer { + --fa: "\f0fc"; + --fa--fa: "\f0fc\f0fc"; } + +.fa-diagram-predecessor { + --fa: "\e477"; + --fa--fa: "\e477\e477"; } + +.fa-arrow-up-long { + --fa: "\f176"; + --fa--fa: "\f176\f176"; } + +.fa-long-arrow-up { + --fa: "\f176"; + --fa--fa: "\f176\f176"; } + +.fa-fire-flame-simple { + --fa: "\f46a"; + --fa--fa: "\f46a\f46a"; } + +.fa-burn { + --fa: "\f46a"; + --fa--fa: "\f46a\f46a"; } + +.fa-person { + --fa: "\f183"; + --fa--fa: "\f183\f183"; } + +.fa-male { + --fa: "\f183"; + --fa--fa: "\f183\f183"; } + +.fa-laptop { + --fa: "\f109"; + --fa--fa: "\f109\f109"; } + +.fa-file-csv { + --fa: "\f6dd"; + --fa--fa: "\f6dd\f6dd"; } + +.fa-menorah { + --fa: "\f676"; + --fa--fa: "\f676\f676"; } + +.fa-truck-plane { + --fa: "\e58f"; + --fa--fa: "\e58f\e58f"; } + +.fa-record-vinyl { + --fa: "\f8d9"; + --fa--fa: "\f8d9\f8d9"; } + +.fa-face-grin-stars { + --fa: "\f587"; + --fa--fa: "\f587\f587"; } + +.fa-grin-stars { + --fa: "\f587"; + --fa--fa: "\f587\f587"; } + +.fa-bong { + --fa: "\f55c"; + --fa--fa: "\f55c\f55c"; } + +.fa-spaghetti-monster-flying { + --fa: "\f67b"; + --fa--fa: "\f67b\f67b"; } + +.fa-pastafarianism { + --fa: "\f67b"; + --fa--fa: "\f67b\f67b"; } + +.fa-arrow-down-up-across-line { + --fa: "\e4af"; + --fa--fa: "\e4af\e4af"; } + +.fa-spoon { + --fa: "\f2e5"; + --fa--fa: "\f2e5\f2e5"; } + +.fa-utensil-spoon { + --fa: "\f2e5"; + --fa--fa: "\f2e5\f2e5"; } + +.fa-jar-wheat { + --fa: "\e517"; + --fa--fa: "\e517\e517"; } + +.fa-envelopes-bulk { + --fa: "\f674"; + --fa--fa: "\f674\f674"; } + +.fa-mail-bulk { + --fa: "\f674"; + --fa--fa: "\f674\f674"; } + +.fa-file-circle-exclamation { + --fa: "\e4eb"; + --fa--fa: "\e4eb\e4eb"; } + +.fa-circle-h { + --fa: "\f47e"; + --fa--fa: "\f47e\f47e"; } + +.fa-hospital-symbol { + --fa: "\f47e"; + --fa--fa: "\f47e\f47e"; } + +.fa-pager { + --fa: "\f815"; + --fa--fa: "\f815\f815"; } + +.fa-address-book { + --fa: "\f2b9"; + --fa--fa: "\f2b9\f2b9"; } + +.fa-contact-book { + --fa: "\f2b9"; + --fa--fa: "\f2b9\f2b9"; } + +.fa-strikethrough { + --fa: "\f0cc"; + --fa--fa: "\f0cc\f0cc"; } + +.fa-k { + --fa: "\4b"; + --fa--fa: "\4b\4b"; } + +.fa-landmark-flag { + --fa: "\e51c"; + --fa--fa: "\e51c\e51c"; } + +.fa-pencil { + --fa: "\f303"; + --fa--fa: "\f303\f303"; } + +.fa-pencil-alt { + --fa: "\f303"; + --fa--fa: "\f303\f303"; } + +.fa-backward { + --fa: "\f04a"; + --fa--fa: "\f04a\f04a"; } + +.fa-caret-right { + --fa: "\f0da"; + --fa--fa: "\f0da\f0da"; } + +.fa-comments { + --fa: "\f086"; + --fa--fa: "\f086\f086"; } + +.fa-paste { + --fa: "\f0ea"; + --fa--fa: "\f0ea\f0ea"; } + +.fa-file-clipboard { + --fa: "\f0ea"; + --fa--fa: "\f0ea\f0ea"; } + +.fa-code-pull-request { + --fa: "\e13c"; + --fa--fa: "\e13c\e13c"; } + +.fa-clipboard-list { + --fa: "\f46d"; + --fa--fa: "\f46d\f46d"; } + +.fa-truck-ramp-box { + --fa: "\f4de"; + --fa--fa: "\f4de\f4de"; } + +.fa-truck-loading { + --fa: "\f4de"; + --fa--fa: "\f4de\f4de"; } + +.fa-user-check { + --fa: "\f4fc"; + --fa--fa: "\f4fc\f4fc"; } + +.fa-vial-virus { + --fa: "\e597"; + --fa--fa: "\e597\e597"; } + +.fa-sheet-plastic { + --fa: "\e571"; + --fa--fa: "\e571\e571"; } + +.fa-blog { + --fa: "\f781"; + --fa--fa: "\f781\f781"; } + +.fa-user-ninja { + --fa: "\f504"; + --fa--fa: "\f504\f504"; } + +.fa-person-arrow-up-from-line { + --fa: "\e539"; + --fa--fa: "\e539\e539"; } + +.fa-scroll-torah { + --fa: "\f6a0"; + --fa--fa: "\f6a0\f6a0"; } + +.fa-torah { + --fa: "\f6a0"; + --fa--fa: "\f6a0\f6a0"; } + +.fa-broom-ball { + --fa: "\f458"; + --fa--fa: "\f458\f458"; } + +.fa-quidditch { + --fa: "\f458"; + --fa--fa: "\f458\f458"; } + +.fa-quidditch-broom-ball { + --fa: "\f458"; + --fa--fa: "\f458\f458"; } + +.fa-toggle-off { + --fa: "\f204"; + --fa--fa: "\f204\f204"; } + +.fa-box-archive { + --fa: "\f187"; + --fa--fa: "\f187\f187"; } + +.fa-archive { + --fa: "\f187"; + --fa--fa: "\f187\f187"; } + +.fa-person-drowning { + --fa: "\e545"; + --fa--fa: "\e545\e545"; } + +.fa-arrow-down-9-1 { + --fa: "\f886"; + --fa--fa: "\f886\f886"; } + +.fa-sort-numeric-desc { + --fa: "\f886"; + --fa--fa: "\f886\f886"; } + +.fa-sort-numeric-down-alt { + --fa: "\f886"; + --fa--fa: "\f886\f886"; } + +.fa-face-grin-tongue-squint { + --fa: "\f58a"; + --fa--fa: "\f58a\f58a"; } + +.fa-grin-tongue-squint { + --fa: "\f58a"; + --fa--fa: "\f58a\f58a"; } + +.fa-spray-can { + --fa: "\f5bd"; + --fa--fa: "\f5bd\f5bd"; } + +.fa-truck-monster { + --fa: "\f63b"; + --fa--fa: "\f63b\f63b"; } + +.fa-w { + --fa: "\57"; + --fa--fa: "\57\57"; } + +.fa-earth-africa { + --fa: "\f57c"; + --fa--fa: "\f57c\f57c"; } + +.fa-globe-africa { + --fa: "\f57c"; + --fa--fa: "\f57c\f57c"; } + +.fa-rainbow { + --fa: "\f75b"; + --fa--fa: "\f75b\f75b"; } + +.fa-circle-notch { + --fa: "\f1ce"; + --fa--fa: "\f1ce\f1ce"; } + +.fa-tablet-screen-button { + --fa: "\f3fa"; + --fa--fa: "\f3fa\f3fa"; } + +.fa-tablet-alt { + --fa: "\f3fa"; + --fa--fa: "\f3fa\f3fa"; } + +.fa-paw { + --fa: "\f1b0"; + --fa--fa: "\f1b0\f1b0"; } + +.fa-cloud { + --fa: "\f0c2"; + --fa--fa: "\f0c2\f0c2"; } + +.fa-trowel-bricks { + --fa: "\e58a"; + --fa--fa: "\e58a\e58a"; } + +.fa-face-flushed { + --fa: "\f579"; + --fa--fa: "\f579\f579"; } + +.fa-flushed { + --fa: "\f579"; + --fa--fa: "\f579\f579"; } + +.fa-hospital-user { + --fa: "\f80d"; + --fa--fa: "\f80d\f80d"; } + +.fa-tent-arrow-left-right { + --fa: "\e57f"; + --fa--fa: "\e57f\e57f"; } + +.fa-gavel { + --fa: "\f0e3"; + --fa--fa: "\f0e3\f0e3"; } + +.fa-legal { + --fa: "\f0e3"; + --fa--fa: "\f0e3\f0e3"; } + +.fa-binoculars { + --fa: "\f1e5"; + --fa--fa: "\f1e5\f1e5"; } + +.fa-microphone-slash { + --fa: "\f131"; + --fa--fa: "\f131\f131"; } + +.fa-box-tissue { + --fa: "\e05b"; + --fa--fa: "\e05b\e05b"; } + +.fa-motorcycle { + --fa: "\f21c"; + --fa--fa: "\f21c\f21c"; } + +.fa-bell-concierge { + --fa: "\f562"; + --fa--fa: "\f562\f562"; } + +.fa-concierge-bell { + --fa: "\f562"; + --fa--fa: "\f562\f562"; } + +.fa-pen-ruler { + --fa: "\f5ae"; + --fa--fa: "\f5ae\f5ae"; } + +.fa-pencil-ruler { + --fa: "\f5ae"; + --fa--fa: "\f5ae\f5ae"; } + +.fa-people-arrows { + --fa: "\e068"; + --fa--fa: "\e068\e068"; } + +.fa-people-arrows-left-right { + --fa: "\e068"; + --fa--fa: "\e068\e068"; } + +.fa-mars-and-venus-burst { + --fa: "\e523"; + --fa--fa: "\e523\e523"; } + +.fa-square-caret-right { + --fa: "\f152"; + --fa--fa: "\f152\f152"; } + +.fa-caret-square-right { + --fa: "\f152"; + --fa--fa: "\f152\f152"; } + +.fa-scissors { + --fa: "\f0c4"; + --fa--fa: "\f0c4\f0c4"; } + +.fa-cut { + --fa: "\f0c4"; + --fa--fa: "\f0c4\f0c4"; } + +.fa-sun-plant-wilt { + --fa: "\e57a"; + --fa--fa: "\e57a\e57a"; } + +.fa-toilets-portable { + --fa: "\e584"; + --fa--fa: "\e584\e584"; } + +.fa-hockey-puck { + --fa: "\f453"; + --fa--fa: "\f453\f453"; } + +.fa-table { + --fa: "\f0ce"; + --fa--fa: "\f0ce\f0ce"; } + +.fa-magnifying-glass-arrow-right { + --fa: "\e521"; + --fa--fa: "\e521\e521"; } + +.fa-tachograph-digital { + --fa: "\f566"; + --fa--fa: "\f566\f566"; } + +.fa-digital-tachograph { + --fa: "\f566"; + --fa--fa: "\f566\f566"; } + +.fa-users-slash { + --fa: "\e073"; + --fa--fa: "\e073\e073"; } + +.fa-clover { + --fa: "\e139"; + --fa--fa: "\e139\e139"; } + +.fa-reply { + --fa: "\f3e5"; + --fa--fa: "\f3e5\f3e5"; } + +.fa-mail-reply { + --fa: "\f3e5"; + --fa--fa: "\f3e5\f3e5"; } + +.fa-star-and-crescent { + --fa: "\f699"; + --fa--fa: "\f699\f699"; } + +.fa-house-fire { + --fa: "\e50c"; + --fa--fa: "\e50c\e50c"; } + +.fa-square-minus { + --fa: "\f146"; + --fa--fa: "\f146\f146"; } + +.fa-minus-square { + --fa: "\f146"; + --fa--fa: "\f146\f146"; } + +.fa-helicopter { + --fa: "\f533"; + --fa--fa: "\f533\f533"; } + +.fa-compass { + --fa: "\f14e"; + --fa--fa: "\f14e\f14e"; } + +.fa-square-caret-down { + --fa: "\f150"; + --fa--fa: "\f150\f150"; } + +.fa-caret-square-down { + --fa: "\f150"; + --fa--fa: "\f150\f150"; } + +.fa-file-circle-question { + --fa: "\e4ef"; + --fa--fa: "\e4ef\e4ef"; } + +.fa-laptop-code { + --fa: "\f5fc"; + --fa--fa: "\f5fc\f5fc"; } + +.fa-swatchbook { + --fa: "\f5c3"; + --fa--fa: "\f5c3\f5c3"; } + +.fa-prescription-bottle { + --fa: "\f485"; + --fa--fa: "\f485\f485"; } + +.fa-bars { + --fa: "\f0c9"; + --fa--fa: "\f0c9\f0c9"; } + +.fa-navicon { + --fa: "\f0c9"; + --fa--fa: "\f0c9\f0c9"; } + +.fa-people-group { + --fa: "\e533"; + --fa--fa: "\e533\e533"; } + +.fa-hourglass-end { + --fa: "\f253"; + --fa--fa: "\f253\f253"; } + +.fa-hourglass-3 { + --fa: "\f253"; + --fa--fa: "\f253\f253"; } + +.fa-heart-crack { + --fa: "\f7a9"; + --fa--fa: "\f7a9\f7a9"; } + +.fa-heart-broken { + --fa: "\f7a9"; + --fa--fa: "\f7a9\f7a9"; } + +.fa-square-up-right { + --fa: "\f360"; + --fa--fa: "\f360\f360"; } + +.fa-external-link-square-alt { + --fa: "\f360"; + --fa--fa: "\f360\f360"; } + +.fa-face-kiss-beam { + --fa: "\f597"; + --fa--fa: "\f597\f597"; } + +.fa-kiss-beam { + --fa: "\f597"; + --fa--fa: "\f597\f597"; } + +.fa-film { + --fa: "\f008"; + --fa--fa: "\f008\f008"; } + +.fa-ruler-horizontal { + --fa: "\f547"; + --fa--fa: "\f547\f547"; } + +.fa-people-robbery { + --fa: "\e536"; + --fa--fa: "\e536\e536"; } + +.fa-lightbulb { + --fa: "\f0eb"; + --fa--fa: "\f0eb\f0eb"; } + +.fa-caret-left { + --fa: "\f0d9"; + --fa--fa: "\f0d9\f0d9"; } + +.fa-circle-exclamation { + --fa: "\f06a"; + --fa--fa: "\f06a\f06a"; } + +.fa-exclamation-circle { + --fa: "\f06a"; + --fa--fa: "\f06a\f06a"; } + +.fa-school-circle-xmark { + --fa: "\e56d"; + --fa--fa: "\e56d\e56d"; } + +.fa-arrow-right-from-bracket { + --fa: "\f08b"; + --fa--fa: "\f08b\f08b"; } + +.fa-sign-out { + --fa: "\f08b"; + --fa--fa: "\f08b\f08b"; } + +.fa-circle-chevron-down { + --fa: "\f13a"; + --fa--fa: "\f13a\f13a"; } + +.fa-chevron-circle-down { + --fa: "\f13a"; + --fa--fa: "\f13a\f13a"; } + +.fa-unlock-keyhole { + --fa: "\f13e"; + --fa--fa: "\f13e\f13e"; } + +.fa-unlock-alt { + --fa: "\f13e"; + --fa--fa: "\f13e\f13e"; } + +.fa-cloud-showers-heavy { + --fa: "\f740"; + --fa--fa: "\f740\f740"; } + +.fa-headphones-simple { + --fa: "\f58f"; + --fa--fa: "\f58f\f58f"; } + +.fa-headphones-alt { + --fa: "\f58f"; + --fa--fa: "\f58f\f58f"; } + +.fa-sitemap { + --fa: "\f0e8"; + --fa--fa: "\f0e8\f0e8"; } + +.fa-circle-dollar-to-slot { + --fa: "\f4b9"; + --fa--fa: "\f4b9\f4b9"; } + +.fa-donate { + --fa: "\f4b9"; + --fa--fa: "\f4b9\f4b9"; } + +.fa-memory { + --fa: "\f538"; + --fa--fa: "\f538\f538"; } + +.fa-road-spikes { + --fa: "\e568"; + --fa--fa: "\e568\e568"; } + +.fa-fire-burner { + --fa: "\e4f1"; + --fa--fa: "\e4f1\e4f1"; } + +.fa-flag { + --fa: "\f024"; + --fa--fa: "\f024\f024"; } + +.fa-hanukiah { + --fa: "\f6e6"; + --fa--fa: "\f6e6\f6e6"; } + +.fa-feather { + --fa: "\f52d"; + --fa--fa: "\f52d\f52d"; } + +.fa-volume-low { + --fa: "\f027"; + --fa--fa: "\f027\f027"; } + +.fa-volume-down { + --fa: "\f027"; + --fa--fa: "\f027\f027"; } + +.fa-comment-slash { + --fa: "\f4b3"; + --fa--fa: "\f4b3\f4b3"; } + +.fa-cloud-sun-rain { + --fa: "\f743"; + --fa--fa: "\f743\f743"; } + +.fa-compress { + --fa: "\f066"; + --fa--fa: "\f066\f066"; } + +.fa-wheat-awn { + --fa: "\e2cd"; + --fa--fa: "\e2cd\e2cd"; } + +.fa-wheat-alt { + --fa: "\e2cd"; + --fa--fa: "\e2cd\e2cd"; } + +.fa-ankh { + --fa: "\f644"; + --fa--fa: "\f644\f644"; } + +.fa-hands-holding-child { + --fa: "\e4fa"; + --fa--fa: "\e4fa\e4fa"; } + +.fa-asterisk { + --fa: "\2a"; + --fa--fa: "\2a\2a"; } + +.fa-square-check { + --fa: "\f14a"; + --fa--fa: "\f14a\f14a"; } + +.fa-check-square { + --fa: "\f14a"; + --fa--fa: "\f14a\f14a"; } + +.fa-peseta-sign { + --fa: "\e221"; + --fa--fa: "\e221\e221"; } + +.fa-heading { + --fa: "\f1dc"; + --fa--fa: "\f1dc\f1dc"; } + +.fa-header { + --fa: "\f1dc"; + --fa--fa: "\f1dc\f1dc"; } + +.fa-ghost { + --fa: "\f6e2"; + --fa--fa: "\f6e2\f6e2"; } + +.fa-list { + --fa: "\f03a"; + --fa--fa: "\f03a\f03a"; } + +.fa-list-squares { + --fa: "\f03a"; + --fa--fa: "\f03a\f03a"; } + +.fa-square-phone-flip { + --fa: "\f87b"; + --fa--fa: "\f87b\f87b"; } + +.fa-phone-square-alt { + --fa: "\f87b"; + --fa--fa: "\f87b\f87b"; } + +.fa-cart-plus { + --fa: "\f217"; + --fa--fa: "\f217\f217"; } + +.fa-gamepad { + --fa: "\f11b"; + --fa--fa: "\f11b\f11b"; } + +.fa-circle-dot { + --fa: "\f192"; + --fa--fa: "\f192\f192"; } + +.fa-dot-circle { + --fa: "\f192"; + --fa--fa: "\f192\f192"; } + +.fa-face-dizzy { + --fa: "\f567"; + --fa--fa: "\f567\f567"; } + +.fa-dizzy { + --fa: "\f567"; + --fa--fa: "\f567\f567"; } + +.fa-egg { + --fa: "\f7fb"; + --fa--fa: "\f7fb\f7fb"; } + +.fa-house-medical-circle-xmark { + --fa: "\e513"; + --fa--fa: "\e513\e513"; } + +.fa-campground { + --fa: "\f6bb"; + --fa--fa: "\f6bb\f6bb"; } + +.fa-folder-plus { + --fa: "\f65e"; + --fa--fa: "\f65e\f65e"; } + +.fa-futbol { + --fa: "\f1e3"; + --fa--fa: "\f1e3\f1e3"; } + +.fa-futbol-ball { + --fa: "\f1e3"; + --fa--fa: "\f1e3\f1e3"; } + +.fa-soccer-ball { + --fa: "\f1e3"; + --fa--fa: "\f1e3\f1e3"; } + +.fa-paintbrush { + --fa: "\f1fc"; + --fa--fa: "\f1fc\f1fc"; } + +.fa-paint-brush { + --fa: "\f1fc"; + --fa--fa: "\f1fc\f1fc"; } + +.fa-lock { + --fa: "\f023"; + --fa--fa: "\f023\f023"; } + +.fa-gas-pump { + --fa: "\f52f"; + --fa--fa: "\f52f\f52f"; } + +.fa-hot-tub-person { + --fa: "\f593"; + --fa--fa: "\f593\f593"; } + +.fa-hot-tub { + --fa: "\f593"; + --fa--fa: "\f593\f593"; } + +.fa-map-location { + --fa: "\f59f"; + --fa--fa: "\f59f\f59f"; } + +.fa-map-marked { + --fa: "\f59f"; + --fa--fa: "\f59f\f59f"; } + +.fa-house-flood-water { + --fa: "\e50e"; + --fa--fa: "\e50e\e50e"; } + +.fa-tree { + --fa: "\f1bb"; + --fa--fa: "\f1bb\f1bb"; } + +.fa-bridge-lock { + --fa: "\e4cc"; + --fa--fa: "\e4cc\e4cc"; } + +.fa-sack-dollar { + --fa: "\f81d"; + --fa--fa: "\f81d\f81d"; } + +.fa-pen-to-square { + --fa: "\f044"; + --fa--fa: "\f044\f044"; } + +.fa-edit { + --fa: "\f044"; + --fa--fa: "\f044\f044"; } + +.fa-car-side { + --fa: "\f5e4"; + --fa--fa: "\f5e4\f5e4"; } + +.fa-share-nodes { + --fa: "\f1e0"; + --fa--fa: "\f1e0\f1e0"; } + +.fa-share-alt { + --fa: "\f1e0"; + --fa--fa: "\f1e0\f1e0"; } + +.fa-heart-circle-minus { + --fa: "\e4ff"; + --fa--fa: "\e4ff\e4ff"; } + +.fa-hourglass-half { + --fa: "\f252"; + --fa--fa: "\f252\f252"; } + +.fa-hourglass-2 { + --fa: "\f252"; + --fa--fa: "\f252\f252"; } + +.fa-microscope { + --fa: "\f610"; + --fa--fa: "\f610\f610"; } + +.fa-sink { + --fa: "\e06d"; + --fa--fa: "\e06d\e06d"; } + +.fa-bag-shopping { + --fa: "\f290"; + --fa--fa: "\f290\f290"; } + +.fa-shopping-bag { + --fa: "\f290"; + --fa--fa: "\f290\f290"; } + +.fa-arrow-down-z-a { + --fa: "\f881"; + --fa--fa: "\f881\f881"; } + +.fa-sort-alpha-desc { + --fa: "\f881"; + --fa--fa: "\f881\f881"; } + +.fa-sort-alpha-down-alt { + --fa: "\f881"; + --fa--fa: "\f881\f881"; } + +.fa-mitten { + --fa: "\f7b5"; + --fa--fa: "\f7b5\f7b5"; } + +.fa-person-rays { + --fa: "\e54d"; + --fa--fa: "\e54d\e54d"; } + +.fa-users { + --fa: "\f0c0"; + --fa--fa: "\f0c0\f0c0"; } + +.fa-eye-slash { + --fa: "\f070"; + --fa--fa: "\f070\f070"; } + +.fa-flask-vial { + --fa: "\e4f3"; + --fa--fa: "\e4f3\e4f3"; } + +.fa-hand { + --fa: "\f256"; + --fa--fa: "\f256\f256"; } + +.fa-hand-paper { + --fa: "\f256"; + --fa--fa: "\f256\f256"; } + +.fa-om { + --fa: "\f679"; + --fa--fa: "\f679\f679"; } + +.fa-worm { + --fa: "\e599"; + --fa--fa: "\e599\e599"; } + +.fa-house-circle-xmark { + --fa: "\e50b"; + --fa--fa: "\e50b\e50b"; } + +.fa-plug { + --fa: "\f1e6"; + --fa--fa: "\f1e6\f1e6"; } + +.fa-chevron-up { + --fa: "\f077"; + --fa--fa: "\f077\f077"; } + +.fa-hand-spock { + --fa: "\f259"; + --fa--fa: "\f259\f259"; } + +.fa-stopwatch { + --fa: "\f2f2"; + --fa--fa: "\f2f2\f2f2"; } + +.fa-face-kiss { + --fa: "\f596"; + --fa--fa: "\f596\f596"; } + +.fa-kiss { + --fa: "\f596"; + --fa--fa: "\f596\f596"; } + +.fa-bridge-circle-xmark { + --fa: "\e4cb"; + --fa--fa: "\e4cb\e4cb"; } + +.fa-face-grin-tongue { + --fa: "\f589"; + --fa--fa: "\f589\f589"; } + +.fa-grin-tongue { + --fa: "\f589"; + --fa--fa: "\f589\f589"; } + +.fa-chess-bishop { + --fa: "\f43a"; + --fa--fa: "\f43a\f43a"; } + +.fa-face-grin-wink { + --fa: "\f58c"; + --fa--fa: "\f58c\f58c"; } + +.fa-grin-wink { + --fa: "\f58c"; + --fa--fa: "\f58c\f58c"; } + +.fa-ear-deaf { + --fa: "\f2a4"; + --fa--fa: "\f2a4\f2a4"; } + +.fa-deaf { + --fa: "\f2a4"; + --fa--fa: "\f2a4\f2a4"; } + +.fa-deafness { + --fa: "\f2a4"; + --fa--fa: "\f2a4\f2a4"; } + +.fa-hard-of-hearing { + --fa: "\f2a4"; + --fa--fa: "\f2a4\f2a4"; } + +.fa-road-circle-check { + --fa: "\e564"; + --fa--fa: "\e564\e564"; } + +.fa-dice-five { + --fa: "\f523"; + --fa--fa: "\f523\f523"; } + +.fa-square-rss { + --fa: "\f143"; + --fa--fa: "\f143\f143"; } + +.fa-rss-square { + --fa: "\f143"; + --fa--fa: "\f143\f143"; } + +.fa-land-mine-on { + --fa: "\e51b"; + --fa--fa: "\e51b\e51b"; } + +.fa-i-cursor { + --fa: "\f246"; + --fa--fa: "\f246\f246"; } + +.fa-stamp { + --fa: "\f5bf"; + --fa--fa: "\f5bf\f5bf"; } + +.fa-stairs { + --fa: "\e289"; + --fa--fa: "\e289\e289"; } + +.fa-i { + --fa: "\49"; + --fa--fa: "\49\49"; } + +.fa-hryvnia-sign { + --fa: "\f6f2"; + --fa--fa: "\f6f2\f6f2"; } + +.fa-hryvnia { + --fa: "\f6f2"; + --fa--fa: "\f6f2\f6f2"; } + +.fa-pills { + --fa: "\f484"; + --fa--fa: "\f484\f484"; } + +.fa-face-grin-wide { + --fa: "\f581"; + --fa--fa: "\f581\f581"; } + +.fa-grin-alt { + --fa: "\f581"; + --fa--fa: "\f581\f581"; } + +.fa-tooth { + --fa: "\f5c9"; + --fa--fa: "\f5c9\f5c9"; } + +.fa-v { + --fa: "\56"; + --fa--fa: "\56\56"; } + +.fa-bangladeshi-taka-sign { + --fa: "\e2e6"; + --fa--fa: "\e2e6\e2e6"; } + +.fa-bicycle { + --fa: "\f206"; + --fa--fa: "\f206\f206"; } + +.fa-staff-snake { + --fa: "\e579"; + --fa--fa: "\e579\e579"; } + +.fa-rod-asclepius { + --fa: "\e579"; + --fa--fa: "\e579\e579"; } + +.fa-rod-snake { + --fa: "\e579"; + --fa--fa: "\e579\e579"; } + +.fa-staff-aesculapius { + --fa: "\e579"; + --fa--fa: "\e579\e579"; } + +.fa-head-side-cough-slash { + --fa: "\e062"; + --fa--fa: "\e062\e062"; } + +.fa-truck-medical { + --fa: "\f0f9"; + --fa--fa: "\f0f9\f0f9"; } + +.fa-ambulance { + --fa: "\f0f9"; + --fa--fa: "\f0f9\f0f9"; } + +.fa-wheat-awn-circle-exclamation { + --fa: "\e598"; + --fa--fa: "\e598\e598"; } + +.fa-snowman { + --fa: "\f7d0"; + --fa--fa: "\f7d0\f7d0"; } + +.fa-mortar-pestle { + --fa: "\f5a7"; + --fa--fa: "\f5a7\f5a7"; } + +.fa-road-barrier { + --fa: "\e562"; + --fa--fa: "\e562\e562"; } + +.fa-school { + --fa: "\f549"; + --fa--fa: "\f549\f549"; } + +.fa-igloo { + --fa: "\f7ae"; + --fa--fa: "\f7ae\f7ae"; } + +.fa-joint { + --fa: "\f595"; + --fa--fa: "\f595\f595"; } + +.fa-angle-right { + --fa: "\f105"; + --fa--fa: "\f105\f105"; } + +.fa-horse { + --fa: "\f6f0"; + --fa--fa: "\f6f0\f6f0"; } + +.fa-q { + --fa: "\51"; + --fa--fa: "\51\51"; } + +.fa-g { + --fa: "\47"; + --fa--fa: "\47\47"; } + +.fa-notes-medical { + --fa: "\f481"; + --fa--fa: "\f481\f481"; } + +.fa-temperature-half { + --fa: "\f2c9"; + --fa--fa: "\f2c9\f2c9"; } + +.fa-temperature-2 { + --fa: "\f2c9"; + --fa--fa: "\f2c9\f2c9"; } + +.fa-thermometer-2 { + --fa: "\f2c9"; + --fa--fa: "\f2c9\f2c9"; } + +.fa-thermometer-half { + --fa: "\f2c9"; + --fa--fa: "\f2c9\f2c9"; } + +.fa-dong-sign { + --fa: "\e169"; + --fa--fa: "\e169\e169"; } + +.fa-capsules { + --fa: "\f46b"; + --fa--fa: "\f46b\f46b"; } + +.fa-poo-storm { + --fa: "\f75a"; + --fa--fa: "\f75a\f75a"; } + +.fa-poo-bolt { + --fa: "\f75a"; + --fa--fa: "\f75a\f75a"; } + +.fa-face-frown-open { + --fa: "\f57a"; + --fa--fa: "\f57a\f57a"; } + +.fa-frown-open { + --fa: "\f57a"; + --fa--fa: "\f57a\f57a"; } + +.fa-hand-point-up { + --fa: "\f0a6"; + --fa--fa: "\f0a6\f0a6"; } + +.fa-money-bill { + --fa: "\f0d6"; + --fa--fa: "\f0d6\f0d6"; } + +.fa-bookmark { + --fa: "\f02e"; + --fa--fa: "\f02e\f02e"; } + +.fa-align-justify { + --fa: "\f039"; + --fa--fa: "\f039\f039"; } + +.fa-umbrella-beach { + --fa: "\f5ca"; + --fa--fa: "\f5ca\f5ca"; } + +.fa-helmet-un { + --fa: "\e503"; + --fa--fa: "\e503\e503"; } + +.fa-bullseye { + --fa: "\f140"; + --fa--fa: "\f140\f140"; } + +.fa-bacon { + --fa: "\f7e5"; + --fa--fa: "\f7e5\f7e5"; } + +.fa-hand-point-down { + --fa: "\f0a7"; + --fa--fa: "\f0a7\f0a7"; } + +.fa-arrow-up-from-bracket { + --fa: "\e09a"; + --fa--fa: "\e09a\e09a"; } + +.fa-folder { + --fa: "\f07b"; + --fa--fa: "\f07b\f07b"; } + +.fa-folder-blank { + --fa: "\f07b"; + --fa--fa: "\f07b\f07b"; } + +.fa-file-waveform { + --fa: "\f478"; + --fa--fa: "\f478\f478"; } + +.fa-file-medical-alt { + --fa: "\f478"; + --fa--fa: "\f478\f478"; } + +.fa-radiation { + --fa: "\f7b9"; + --fa--fa: "\f7b9\f7b9"; } + +.fa-chart-simple { + --fa: "\e473"; + --fa--fa: "\e473\e473"; } + +.fa-mars-stroke { + --fa: "\f229"; + --fa--fa: "\f229\f229"; } + +.fa-vial { + --fa: "\f492"; + --fa--fa: "\f492\f492"; } + +.fa-gauge { + --fa: "\f624"; + --fa--fa: "\f624\f624"; } + +.fa-dashboard { + --fa: "\f624"; + --fa--fa: "\f624\f624"; } + +.fa-gauge-med { + --fa: "\f624"; + --fa--fa: "\f624\f624"; } + +.fa-tachometer-alt-average { + --fa: "\f624"; + --fa--fa: "\f624\f624"; } + +.fa-wand-magic-sparkles { + --fa: "\e2ca"; + --fa--fa: "\e2ca\e2ca"; } + +.fa-magic-wand-sparkles { + --fa: "\e2ca"; + --fa--fa: "\e2ca\e2ca"; } + +.fa-e { + --fa: "\45"; + --fa--fa: "\45\45"; } + +.fa-pen-clip { + --fa: "\f305"; + --fa--fa: "\f305\f305"; } + +.fa-pen-alt { + --fa: "\f305"; + --fa--fa: "\f305\f305"; } + +.fa-bridge-circle-exclamation { + --fa: "\e4ca"; + --fa--fa: "\e4ca\e4ca"; } + +.fa-user { + --fa: "\f007"; + --fa--fa: "\f007\f007"; } + +.fa-school-circle-check { + --fa: "\e56b"; + --fa--fa: "\e56b\e56b"; } + +.fa-dumpster { + --fa: "\f793"; + --fa--fa: "\f793\f793"; } + +.fa-van-shuttle { + --fa: "\f5b6"; + --fa--fa: "\f5b6\f5b6"; } + +.fa-shuttle-van { + --fa: "\f5b6"; + --fa--fa: "\f5b6\f5b6"; } + +.fa-building-user { + --fa: "\e4da"; + --fa--fa: "\e4da\e4da"; } + +.fa-square-caret-left { + --fa: "\f191"; + --fa--fa: "\f191\f191"; } + +.fa-caret-square-left { + --fa: "\f191"; + --fa--fa: "\f191\f191"; } + +.fa-highlighter { + --fa: "\f591"; + --fa--fa: "\f591\f591"; } + +.fa-key { + --fa: "\f084"; + --fa--fa: "\f084\f084"; } + +.fa-bullhorn { + --fa: "\f0a1"; + --fa--fa: "\f0a1\f0a1"; } + +.fa-globe { + --fa: "\f0ac"; + --fa--fa: "\f0ac\f0ac"; } + +.fa-synagogue { + --fa: "\f69b"; + --fa--fa: "\f69b\f69b"; } + +.fa-person-half-dress { + --fa: "\e548"; + --fa--fa: "\e548\e548"; } + +.fa-road-bridge { + --fa: "\e563"; + --fa--fa: "\e563\e563"; } + +.fa-location-arrow { + --fa: "\f124"; + --fa--fa: "\f124\f124"; } + +.fa-c { + --fa: "\43"; + --fa--fa: "\43\43"; } + +.fa-tablet-button { + --fa: "\f10a"; + --fa--fa: "\f10a\f10a"; } + +.fa-building-lock { + --fa: "\e4d6"; + --fa--fa: "\e4d6\e4d6"; } + +.fa-pizza-slice { + --fa: "\f818"; + --fa--fa: "\f818\f818"; } + +.fa-money-bill-wave { + --fa: "\f53a"; + --fa--fa: "\f53a\f53a"; } + +.fa-chart-area { + --fa: "\f1fe"; + --fa--fa: "\f1fe\f1fe"; } + +.fa-area-chart { + --fa: "\f1fe"; + --fa--fa: "\f1fe\f1fe"; } + +.fa-house-flag { + --fa: "\e50d"; + --fa--fa: "\e50d\e50d"; } + +.fa-person-circle-minus { + --fa: "\e540"; + --fa--fa: "\e540\e540"; } + +.fa-ban { + --fa: "\f05e"; + --fa--fa: "\f05e\f05e"; } + +.fa-cancel { + --fa: "\f05e"; + --fa--fa: "\f05e\f05e"; } + +.fa-camera-rotate { + --fa: "\e0d8"; + --fa--fa: "\e0d8\e0d8"; } + +.fa-spray-can-sparkles { + --fa: "\f5d0"; + --fa--fa: "\f5d0\f5d0"; } + +.fa-air-freshener { + --fa: "\f5d0"; + --fa--fa: "\f5d0\f5d0"; } + +.fa-star { + --fa: "\f005"; + --fa--fa: "\f005\f005"; } + +.fa-repeat { + --fa: "\f363"; + --fa--fa: "\f363\f363"; } + +.fa-cross { + --fa: "\f654"; + --fa--fa: "\f654\f654"; } + +.fa-box { + --fa: "\f466"; + --fa--fa: "\f466\f466"; } + +.fa-venus-mars { + --fa: "\f228"; + --fa--fa: "\f228\f228"; } + +.fa-arrow-pointer { + --fa: "\f245"; + --fa--fa: "\f245\f245"; } + +.fa-mouse-pointer { + --fa: "\f245"; + --fa--fa: "\f245\f245"; } + +.fa-maximize { + --fa: "\f31e"; + --fa--fa: "\f31e\f31e"; } + +.fa-expand-arrows-alt { + --fa: "\f31e"; + --fa--fa: "\f31e\f31e"; } + +.fa-charging-station { + --fa: "\f5e7"; + --fa--fa: "\f5e7\f5e7"; } + +.fa-shapes { + --fa: "\f61f"; + --fa--fa: "\f61f\f61f"; } + +.fa-triangle-circle-square { + --fa: "\f61f"; + --fa--fa: "\f61f\f61f"; } + +.fa-shuffle { + --fa: "\f074"; + --fa--fa: "\f074\f074"; } + +.fa-random { + --fa: "\f074"; + --fa--fa: "\f074\f074"; } + +.fa-person-running { + --fa: "\f70c"; + --fa--fa: "\f70c\f70c"; } + +.fa-running { + --fa: "\f70c"; + --fa--fa: "\f70c\f70c"; } + +.fa-mobile-retro { + --fa: "\e527"; + --fa--fa: "\e527\e527"; } + +.fa-grip-lines-vertical { + --fa: "\f7a5"; + --fa--fa: "\f7a5\f7a5"; } + +.fa-spider { + --fa: "\f717"; + --fa--fa: "\f717\f717"; } + +.fa-hands-bound { + --fa: "\e4f9"; + --fa--fa: "\e4f9\e4f9"; } + +.fa-file-invoice-dollar { + --fa: "\f571"; + --fa--fa: "\f571\f571"; } + +.fa-plane-circle-exclamation { + --fa: "\e556"; + --fa--fa: "\e556\e556"; } + +.fa-x-ray { + --fa: "\f497"; + --fa--fa: "\f497\f497"; } + +.fa-spell-check { + --fa: "\f891"; + --fa--fa: "\f891\f891"; } + +.fa-slash { + --fa: "\f715"; + --fa--fa: "\f715\f715"; } + +.fa-computer-mouse { + --fa: "\f8cc"; + --fa--fa: "\f8cc\f8cc"; } + +.fa-mouse { + --fa: "\f8cc"; + --fa--fa: "\f8cc\f8cc"; } + +.fa-arrow-right-to-bracket { + --fa: "\f090"; + --fa--fa: "\f090\f090"; } + +.fa-sign-in { + --fa: "\f090"; + --fa--fa: "\f090\f090"; } + +.fa-shop-slash { + --fa: "\e070"; + --fa--fa: "\e070\e070"; } + +.fa-store-alt-slash { + --fa: "\e070"; + --fa--fa: "\e070\e070"; } + +.fa-server { + --fa: "\f233"; + --fa--fa: "\f233\f233"; } + +.fa-virus-covid-slash { + --fa: "\e4a9"; + --fa--fa: "\e4a9\e4a9"; } + +.fa-shop-lock { + --fa: "\e4a5"; + --fa--fa: "\e4a5\e4a5"; } + +.fa-hourglass-start { + --fa: "\f251"; + --fa--fa: "\f251\f251"; } + +.fa-hourglass-1 { + --fa: "\f251"; + --fa--fa: "\f251\f251"; } + +.fa-blender-phone { + --fa: "\f6b6"; + --fa--fa: "\f6b6\f6b6"; } + +.fa-building-wheat { + --fa: "\e4db"; + --fa--fa: "\e4db\e4db"; } + +.fa-person-breastfeeding { + --fa: "\e53a"; + --fa--fa: "\e53a\e53a"; } + +.fa-right-to-bracket { + --fa: "\f2f6"; + --fa--fa: "\f2f6\f2f6"; } + +.fa-sign-in-alt { + --fa: "\f2f6"; + --fa--fa: "\f2f6\f2f6"; } + +.fa-venus { + --fa: "\f221"; + --fa--fa: "\f221\f221"; } + +.fa-passport { + --fa: "\f5ab"; + --fa--fa: "\f5ab\f5ab"; } + +.fa-thumbtack-slash { + --fa: "\e68f"; + --fa--fa: "\e68f\e68f"; } + +.fa-thumb-tack-slash { + --fa: "\e68f"; + --fa--fa: "\e68f\e68f"; } + +.fa-heart-pulse { + --fa: "\f21e"; + --fa--fa: "\f21e\f21e"; } + +.fa-heartbeat { + --fa: "\f21e"; + --fa--fa: "\f21e\f21e"; } + +.fa-people-carry-box { + --fa: "\f4ce"; + --fa--fa: "\f4ce\f4ce"; } + +.fa-people-carry { + --fa: "\f4ce"; + --fa--fa: "\f4ce\f4ce"; } + +.fa-temperature-high { + --fa: "\f769"; + --fa--fa: "\f769\f769"; } + +.fa-microchip { + --fa: "\f2db"; + --fa--fa: "\f2db\f2db"; } + +.fa-crown { + --fa: "\f521"; + --fa--fa: "\f521\f521"; } + +.fa-weight-hanging { + --fa: "\f5cd"; + --fa--fa: "\f5cd\f5cd"; } + +.fa-xmarks-lines { + --fa: "\e59a"; + --fa--fa: "\e59a\e59a"; } + +.fa-file-prescription { + --fa: "\f572"; + --fa--fa: "\f572\f572"; } + +.fa-weight-scale { + --fa: "\f496"; + --fa--fa: "\f496\f496"; } + +.fa-weight { + --fa: "\f496"; + --fa--fa: "\f496\f496"; } + +.fa-user-group { + --fa: "\f500"; + --fa--fa: "\f500\f500"; } + +.fa-user-friends { + --fa: "\f500"; + --fa--fa: "\f500\f500"; } + +.fa-arrow-up-a-z { + --fa: "\f15e"; + --fa--fa: "\f15e\f15e"; } + +.fa-sort-alpha-up { + --fa: "\f15e"; + --fa--fa: "\f15e\f15e"; } + +.fa-chess-knight { + --fa: "\f441"; + --fa--fa: "\f441\f441"; } + +.fa-face-laugh-squint { + --fa: "\f59b"; + --fa--fa: "\f59b\f59b"; } + +.fa-laugh-squint { + --fa: "\f59b"; + --fa--fa: "\f59b\f59b"; } + +.fa-wheelchair { + --fa: "\f193"; + --fa--fa: "\f193\f193"; } + +.fa-circle-arrow-up { + --fa: "\f0aa"; + --fa--fa: "\f0aa\f0aa"; } + +.fa-arrow-circle-up { + --fa: "\f0aa"; + --fa--fa: "\f0aa\f0aa"; } + +.fa-toggle-on { + --fa: "\f205"; + --fa--fa: "\f205\f205"; } + +.fa-person-walking { + --fa: "\f554"; + --fa--fa: "\f554\f554"; } + +.fa-walking { + --fa: "\f554"; + --fa--fa: "\f554\f554"; } + +.fa-l { + --fa: "\4c"; + --fa--fa: "\4c\4c"; } + +.fa-fire { + --fa: "\f06d"; + --fa--fa: "\f06d\f06d"; } + +.fa-bed-pulse { + --fa: "\f487"; + --fa--fa: "\f487\f487"; } + +.fa-procedures { + --fa: "\f487"; + --fa--fa: "\f487\f487"; } + +.fa-shuttle-space { + --fa: "\f197"; + --fa--fa: "\f197\f197"; } + +.fa-space-shuttle { + --fa: "\f197"; + --fa--fa: "\f197\f197"; } + +.fa-face-laugh { + --fa: "\f599"; + --fa--fa: "\f599\f599"; } + +.fa-laugh { + --fa: "\f599"; + --fa--fa: "\f599\f599"; } + +.fa-folder-open { + --fa: "\f07c"; + --fa--fa: "\f07c\f07c"; } + +.fa-heart-circle-plus { + --fa: "\e500"; + --fa--fa: "\e500\e500"; } + +.fa-code-fork { + --fa: "\e13b"; + --fa--fa: "\e13b\e13b"; } + +.fa-city { + --fa: "\f64f"; + --fa--fa: "\f64f\f64f"; } + +.fa-microphone-lines { + --fa: "\f3c9"; + --fa--fa: "\f3c9\f3c9"; } + +.fa-microphone-alt { + --fa: "\f3c9"; + --fa--fa: "\f3c9\f3c9"; } + +.fa-pepper-hot { + --fa: "\f816"; + --fa--fa: "\f816\f816"; } + +.fa-unlock { + --fa: "\f09c"; + --fa--fa: "\f09c\f09c"; } + +.fa-colon-sign { + --fa: "\e140"; + --fa--fa: "\e140\e140"; } + +.fa-headset { + --fa: "\f590"; + --fa--fa: "\f590\f590"; } + +.fa-store-slash { + --fa: "\e071"; + --fa--fa: "\e071\e071"; } + +.fa-road-circle-xmark { + --fa: "\e566"; + --fa--fa: "\e566\e566"; } + +.fa-user-minus { + --fa: "\f503"; + --fa--fa: "\f503\f503"; } + +.fa-mars-stroke-up { + --fa: "\f22a"; + --fa--fa: "\f22a\f22a"; } + +.fa-mars-stroke-v { + --fa: "\f22a"; + --fa--fa: "\f22a\f22a"; } + +.fa-champagne-glasses { + --fa: "\f79f"; + --fa--fa: "\f79f\f79f"; } + +.fa-glass-cheers { + --fa: "\f79f"; + --fa--fa: "\f79f\f79f"; } + +.fa-clipboard { + --fa: "\f328"; + --fa--fa: "\f328\f328"; } + +.fa-house-circle-exclamation { + --fa: "\e50a"; + --fa--fa: "\e50a\e50a"; } + +.fa-file-arrow-up { + --fa: "\f574"; + --fa--fa: "\f574\f574"; } + +.fa-file-upload { + --fa: "\f574"; + --fa--fa: "\f574\f574"; } + +.fa-wifi { + --fa: "\f1eb"; + --fa--fa: "\f1eb\f1eb"; } + +.fa-wifi-3 { + --fa: "\f1eb"; + --fa--fa: "\f1eb\f1eb"; } + +.fa-wifi-strong { + --fa: "\f1eb"; + --fa--fa: "\f1eb\f1eb"; } + +.fa-bath { + --fa: "\f2cd"; + --fa--fa: "\f2cd\f2cd"; } + +.fa-bathtub { + --fa: "\f2cd"; + --fa--fa: "\f2cd\f2cd"; } + +.fa-underline { + --fa: "\f0cd"; + --fa--fa: "\f0cd\f0cd"; } + +.fa-user-pen { + --fa: "\f4ff"; + --fa--fa: "\f4ff\f4ff"; } + +.fa-user-edit { + --fa: "\f4ff"; + --fa--fa: "\f4ff\f4ff"; } + +.fa-signature { + --fa: "\f5b7"; + --fa--fa: "\f5b7\f5b7"; } + +.fa-stroopwafel { + --fa: "\f551"; + --fa--fa: "\f551\f551"; } + +.fa-bold { + --fa: "\f032"; + --fa--fa: "\f032\f032"; } + +.fa-anchor-lock { + --fa: "\e4ad"; + --fa--fa: "\e4ad\e4ad"; } + +.fa-building-ngo { + --fa: "\e4d7"; + --fa--fa: "\e4d7\e4d7"; } + +.fa-manat-sign { + --fa: "\e1d5"; + --fa--fa: "\e1d5\e1d5"; } + +.fa-not-equal { + --fa: "\f53e"; + --fa--fa: "\f53e\f53e"; } + +.fa-border-top-left { + --fa: "\f853"; + --fa--fa: "\f853\f853"; } + +.fa-border-style { + --fa: "\f853"; + --fa--fa: "\f853\f853"; } + +.fa-map-location-dot { + --fa: "\f5a0"; + --fa--fa: "\f5a0\f5a0"; } + +.fa-map-marked-alt { + --fa: "\f5a0"; + --fa--fa: "\f5a0\f5a0"; } + +.fa-jedi { + --fa: "\f669"; + --fa--fa: "\f669\f669"; } + +.fa-square-poll-vertical { + --fa: "\f681"; + --fa--fa: "\f681\f681"; } + +.fa-poll { + --fa: "\f681"; + --fa--fa: "\f681\f681"; } + +.fa-mug-hot { + --fa: "\f7b6"; + --fa--fa: "\f7b6\f7b6"; } + +.fa-car-battery { + --fa: "\f5df"; + --fa--fa: "\f5df\f5df"; } + +.fa-battery-car { + --fa: "\f5df"; + --fa--fa: "\f5df\f5df"; } + +.fa-gift { + --fa: "\f06b"; + --fa--fa: "\f06b\f06b"; } + +.fa-dice-two { + --fa: "\f528"; + --fa--fa: "\f528\f528"; } + +.fa-chess-queen { + --fa: "\f445"; + --fa--fa: "\f445\f445"; } + +.fa-glasses { + --fa: "\f530"; + --fa--fa: "\f530\f530"; } + +.fa-chess-board { + --fa: "\f43c"; + --fa--fa: "\f43c\f43c"; } + +.fa-building-circle-check { + --fa: "\e4d2"; + --fa--fa: "\e4d2\e4d2"; } + +.fa-person-chalkboard { + --fa: "\e53d"; + --fa--fa: "\e53d\e53d"; } + +.fa-mars-stroke-right { + --fa: "\f22b"; + --fa--fa: "\f22b\f22b"; } + +.fa-mars-stroke-h { + --fa: "\f22b"; + --fa--fa: "\f22b\f22b"; } + +.fa-hand-back-fist { + --fa: "\f255"; + --fa--fa: "\f255\f255"; } + +.fa-hand-rock { + --fa: "\f255"; + --fa--fa: "\f255\f255"; } + +.fa-square-caret-up { + --fa: "\f151"; + --fa--fa: "\f151\f151"; } + +.fa-caret-square-up { + --fa: "\f151"; + --fa--fa: "\f151\f151"; } + +.fa-cloud-showers-water { + --fa: "\e4e4"; + --fa--fa: "\e4e4\e4e4"; } + +.fa-chart-bar { + --fa: "\f080"; + --fa--fa: "\f080\f080"; } + +.fa-bar-chart { + --fa: "\f080"; + --fa--fa: "\f080\f080"; } + +.fa-hands-bubbles { + --fa: "\e05e"; + --fa--fa: "\e05e\e05e"; } + +.fa-hands-wash { + --fa: "\e05e"; + --fa--fa: "\e05e\e05e"; } + +.fa-less-than-equal { + --fa: "\f537"; + --fa--fa: "\f537\f537"; } + +.fa-train { + --fa: "\f238"; + --fa--fa: "\f238\f238"; } + +.fa-eye-low-vision { + --fa: "\f2a8"; + --fa--fa: "\f2a8\f2a8"; } + +.fa-low-vision { + --fa: "\f2a8"; + --fa--fa: "\f2a8\f2a8"; } + +.fa-crow { + --fa: "\f520"; + --fa--fa: "\f520\f520"; } + +.fa-sailboat { + --fa: "\e445"; + --fa--fa: "\e445\e445"; } + +.fa-window-restore { + --fa: "\f2d2"; + --fa--fa: "\f2d2\f2d2"; } + +.fa-square-plus { + --fa: "\f0fe"; + --fa--fa: "\f0fe\f0fe"; } + +.fa-plus-square { + --fa: "\f0fe"; + --fa--fa: "\f0fe\f0fe"; } + +.fa-torii-gate { + --fa: "\f6a1"; + --fa--fa: "\f6a1\f6a1"; } + +.fa-frog { + --fa: "\f52e"; + --fa--fa: "\f52e\f52e"; } + +.fa-bucket { + --fa: "\e4cf"; + --fa--fa: "\e4cf\e4cf"; } + +.fa-image { + --fa: "\f03e"; + --fa--fa: "\f03e\f03e"; } + +.fa-microphone { + --fa: "\f130"; + --fa--fa: "\f130\f130"; } + +.fa-cow { + --fa: "\f6c8"; + --fa--fa: "\f6c8\f6c8"; } + +.fa-caret-up { + --fa: "\f0d8"; + --fa--fa: "\f0d8\f0d8"; } + +.fa-screwdriver { + --fa: "\f54a"; + --fa--fa: "\f54a\f54a"; } + +.fa-folder-closed { + --fa: "\e185"; + --fa--fa: "\e185\e185"; } + +.fa-house-tsunami { + --fa: "\e515"; + --fa--fa: "\e515\e515"; } + +.fa-square-nfi { + --fa: "\e576"; + --fa--fa: "\e576\e576"; } + +.fa-arrow-up-from-ground-water { + --fa: "\e4b5"; + --fa--fa: "\e4b5\e4b5"; } + +.fa-martini-glass { + --fa: "\f57b"; + --fa--fa: "\f57b\f57b"; } + +.fa-glass-martini-alt { + --fa: "\f57b"; + --fa--fa: "\f57b\f57b"; } + +.fa-square-binary { + --fa: "\e69b"; + --fa--fa: "\e69b\e69b"; } + +.fa-rotate-left { + --fa: "\f2ea"; + --fa--fa: "\f2ea\f2ea"; } + +.fa-rotate-back { + --fa: "\f2ea"; + --fa--fa: "\f2ea\f2ea"; } + +.fa-rotate-backward { + --fa: "\f2ea"; + --fa--fa: "\f2ea\f2ea"; } + +.fa-undo-alt { + --fa: "\f2ea"; + --fa--fa: "\f2ea\f2ea"; } + +.fa-table-columns { + --fa: "\f0db"; + --fa--fa: "\f0db\f0db"; } + +.fa-columns { + --fa: "\f0db"; + --fa--fa: "\f0db\f0db"; } + +.fa-lemon { + --fa: "\f094"; + --fa--fa: "\f094\f094"; } + +.fa-head-side-mask { + --fa: "\e063"; + --fa--fa: "\e063\e063"; } + +.fa-handshake { + --fa: "\f2b5"; + --fa--fa: "\f2b5\f2b5"; } + +.fa-gem { + --fa: "\f3a5"; + --fa--fa: "\f3a5\f3a5"; } + +.fa-dolly { + --fa: "\f472"; + --fa--fa: "\f472\f472"; } + +.fa-dolly-box { + --fa: "\f472"; + --fa--fa: "\f472\f472"; } + +.fa-smoking { + --fa: "\f48d"; + --fa--fa: "\f48d\f48d"; } + +.fa-minimize { + --fa: "\f78c"; + --fa--fa: "\f78c\f78c"; } + +.fa-compress-arrows-alt { + --fa: "\f78c"; + --fa--fa: "\f78c\f78c"; } + +.fa-monument { + --fa: "\f5a6"; + --fa--fa: "\f5a6\f5a6"; } + +.fa-snowplow { + --fa: "\f7d2"; + --fa--fa: "\f7d2\f7d2"; } + +.fa-angles-right { + --fa: "\f101"; + --fa--fa: "\f101\f101"; } + +.fa-angle-double-right { + --fa: "\f101"; + --fa--fa: "\f101\f101"; } + +.fa-cannabis { + --fa: "\f55f"; + --fa--fa: "\f55f\f55f"; } + +.fa-circle-play { + --fa: "\f144"; + --fa--fa: "\f144\f144"; } + +.fa-play-circle { + --fa: "\f144"; + --fa--fa: "\f144\f144"; } + +.fa-tablets { + --fa: "\f490"; + --fa--fa: "\f490\f490"; } + +.fa-ethernet { + --fa: "\f796"; + --fa--fa: "\f796\f796"; } + +.fa-euro-sign { + --fa: "\f153"; + --fa--fa: "\f153\f153"; } + +.fa-eur { + --fa: "\f153"; + --fa--fa: "\f153\f153"; } + +.fa-euro { + --fa: "\f153"; + --fa--fa: "\f153\f153"; } + +.fa-chair { + --fa: "\f6c0"; + --fa--fa: "\f6c0\f6c0"; } + +.fa-circle-check { + --fa: "\f058"; + --fa--fa: "\f058\f058"; } + +.fa-check-circle { + --fa: "\f058"; + --fa--fa: "\f058\f058"; } + +.fa-circle-stop { + --fa: "\f28d"; + --fa--fa: "\f28d\f28d"; } + +.fa-stop-circle { + --fa: "\f28d"; + --fa--fa: "\f28d\f28d"; } + +.fa-compass-drafting { + --fa: "\f568"; + --fa--fa: "\f568\f568"; } + +.fa-drafting-compass { + --fa: "\f568"; + --fa--fa: "\f568\f568"; } + +.fa-plate-wheat { + --fa: "\e55a"; + --fa--fa: "\e55a\e55a"; } + +.fa-icicles { + --fa: "\f7ad"; + --fa--fa: "\f7ad\f7ad"; } + +.fa-person-shelter { + --fa: "\e54f"; + --fa--fa: "\e54f\e54f"; } + +.fa-neuter { + --fa: "\f22c"; + --fa--fa: "\f22c\f22c"; } + +.fa-id-badge { + --fa: "\f2c1"; + --fa--fa: "\f2c1\f2c1"; } + +.fa-marker { + --fa: "\f5a1"; + --fa--fa: "\f5a1\f5a1"; } + +.fa-face-laugh-beam { + --fa: "\f59a"; + --fa--fa: "\f59a\f59a"; } + +.fa-laugh-beam { + --fa: "\f59a"; + --fa--fa: "\f59a\f59a"; } + +.fa-helicopter-symbol { + --fa: "\e502"; + --fa--fa: "\e502\e502"; } + +.fa-universal-access { + --fa: "\f29a"; + --fa--fa: "\f29a\f29a"; } + +.fa-circle-chevron-up { + --fa: "\f139"; + --fa--fa: "\f139\f139"; } + +.fa-chevron-circle-up { + --fa: "\f139"; + --fa--fa: "\f139\f139"; } + +.fa-lari-sign { + --fa: "\e1c8"; + --fa--fa: "\e1c8\e1c8"; } + +.fa-volcano { + --fa: "\f770"; + --fa--fa: "\f770\f770"; } + +.fa-person-walking-dashed-line-arrow-right { + --fa: "\e553"; + --fa--fa: "\e553\e553"; } + +.fa-sterling-sign { + --fa: "\f154"; + --fa--fa: "\f154\f154"; } + +.fa-gbp { + --fa: "\f154"; + --fa--fa: "\f154\f154"; } + +.fa-pound-sign { + --fa: "\f154"; + --fa--fa: "\f154\f154"; } + +.fa-viruses { + --fa: "\e076"; + --fa--fa: "\e076\e076"; } + +.fa-square-person-confined { + --fa: "\e577"; + --fa--fa: "\e577\e577"; } + +.fa-user-tie { + --fa: "\f508"; + --fa--fa: "\f508\f508"; } + +.fa-arrow-down-long { + --fa: "\f175"; + --fa--fa: "\f175\f175"; } + +.fa-long-arrow-down { + --fa: "\f175"; + --fa--fa: "\f175\f175"; } + +.fa-tent-arrow-down-to-line { + --fa: "\e57e"; + --fa--fa: "\e57e\e57e"; } + +.fa-certificate { + --fa: "\f0a3"; + --fa--fa: "\f0a3\f0a3"; } + +.fa-reply-all { + --fa: "\f122"; + --fa--fa: "\f122\f122"; } + +.fa-mail-reply-all { + --fa: "\f122"; + --fa--fa: "\f122\f122"; } + +.fa-suitcase { + --fa: "\f0f2"; + --fa--fa: "\f0f2\f0f2"; } + +.fa-person-skating { + --fa: "\f7c5"; + --fa--fa: "\f7c5\f7c5"; } + +.fa-skating { + --fa: "\f7c5"; + --fa--fa: "\f7c5\f7c5"; } + +.fa-filter-circle-dollar { + --fa: "\f662"; + --fa--fa: "\f662\f662"; } + +.fa-funnel-dollar { + --fa: "\f662"; + --fa--fa: "\f662\f662"; } + +.fa-camera-retro { + --fa: "\f083"; + --fa--fa: "\f083\f083"; } + +.fa-circle-arrow-down { + --fa: "\f0ab"; + --fa--fa: "\f0ab\f0ab"; } + +.fa-arrow-circle-down { + --fa: "\f0ab"; + --fa--fa: "\f0ab\f0ab"; } + +.fa-file-import { + --fa: "\f56f"; + --fa--fa: "\f56f\f56f"; } + +.fa-arrow-right-to-file { + --fa: "\f56f"; + --fa--fa: "\f56f\f56f"; } + +.fa-square-arrow-up-right { + --fa: "\f14c"; + --fa--fa: "\f14c\f14c"; } + +.fa-external-link-square { + --fa: "\f14c"; + --fa--fa: "\f14c\f14c"; } + +.fa-box-open { + --fa: "\f49e"; + --fa--fa: "\f49e\f49e"; } + +.fa-scroll { + --fa: "\f70e"; + --fa--fa: "\f70e\f70e"; } + +.fa-spa { + --fa: "\f5bb"; + --fa--fa: "\f5bb\f5bb"; } + +.fa-location-pin-lock { + --fa: "\e51f"; + --fa--fa: "\e51f\e51f"; } + +.fa-pause { + --fa: "\f04c"; + --fa--fa: "\f04c\f04c"; } + +.fa-hill-avalanche { + --fa: "\e507"; + --fa--fa: "\e507\e507"; } + +.fa-temperature-empty { + --fa: "\f2cb"; + --fa--fa: "\f2cb\f2cb"; } + +.fa-temperature-0 { + --fa: "\f2cb"; + --fa--fa: "\f2cb\f2cb"; } + +.fa-thermometer-0 { + --fa: "\f2cb"; + --fa--fa: "\f2cb\f2cb"; } + +.fa-thermometer-empty { + --fa: "\f2cb"; + --fa--fa: "\f2cb\f2cb"; } + +.fa-bomb { + --fa: "\f1e2"; + --fa--fa: "\f1e2\f1e2"; } + +.fa-registered { + --fa: "\f25d"; + --fa--fa: "\f25d\f25d"; } + +.fa-address-card { + --fa: "\f2bb"; + --fa--fa: "\f2bb\f2bb"; } + +.fa-contact-card { + --fa: "\f2bb"; + --fa--fa: "\f2bb\f2bb"; } + +.fa-vcard { + --fa: "\f2bb"; + --fa--fa: "\f2bb\f2bb"; } + +.fa-scale-unbalanced-flip { + --fa: "\f516"; + --fa--fa: "\f516\f516"; } + +.fa-balance-scale-right { + --fa: "\f516"; + --fa--fa: "\f516\f516"; } + +.fa-subscript { + --fa: "\f12c"; + --fa--fa: "\f12c\f12c"; } + +.fa-diamond-turn-right { + --fa: "\f5eb"; + --fa--fa: "\f5eb\f5eb"; } + +.fa-directions { + --fa: "\f5eb"; + --fa--fa: "\f5eb\f5eb"; } + +.fa-burst { + --fa: "\e4dc"; + --fa--fa: "\e4dc\e4dc"; } + +.fa-house-laptop { + --fa: "\e066"; + --fa--fa: "\e066\e066"; } + +.fa-laptop-house { + --fa: "\e066"; + --fa--fa: "\e066\e066"; } + +.fa-face-tired { + --fa: "\f5c8"; + --fa--fa: "\f5c8\f5c8"; } + +.fa-tired { + --fa: "\f5c8"; + --fa--fa: "\f5c8\f5c8"; } + +.fa-money-bills { + --fa: "\e1f3"; + --fa--fa: "\e1f3\e1f3"; } + +.fa-smog { + --fa: "\f75f"; + --fa--fa: "\f75f\f75f"; } + +.fa-crutch { + --fa: "\f7f7"; + --fa--fa: "\f7f7\f7f7"; } + +.fa-cloud-arrow-up { + --fa: "\f0ee"; + --fa--fa: "\f0ee\f0ee"; } + +.fa-cloud-upload { + --fa: "\f0ee"; + --fa--fa: "\f0ee\f0ee"; } + +.fa-cloud-upload-alt { + --fa: "\f0ee"; + --fa--fa: "\f0ee\f0ee"; } + +.fa-palette { + --fa: "\f53f"; + --fa--fa: "\f53f\f53f"; } + +.fa-arrows-turn-right { + --fa: "\e4c0"; + --fa--fa: "\e4c0\e4c0"; } + +.fa-vest { + --fa: "\e085"; + --fa--fa: "\e085\e085"; } + +.fa-ferry { + --fa: "\e4ea"; + --fa--fa: "\e4ea\e4ea"; } + +.fa-arrows-down-to-people { + --fa: "\e4b9"; + --fa--fa: "\e4b9\e4b9"; } + +.fa-seedling { + --fa: "\f4d8"; + --fa--fa: "\f4d8\f4d8"; } + +.fa-sprout { + --fa: "\f4d8"; + --fa--fa: "\f4d8\f4d8"; } + +.fa-left-right { + --fa: "\f337"; + --fa--fa: "\f337\f337"; } + +.fa-arrows-alt-h { + --fa: "\f337"; + --fa--fa: "\f337\f337"; } + +.fa-boxes-packing { + --fa: "\e4c7"; + --fa--fa: "\e4c7\e4c7"; } + +.fa-circle-arrow-left { + --fa: "\f0a8"; + --fa--fa: "\f0a8\f0a8"; } + +.fa-arrow-circle-left { + --fa: "\f0a8"; + --fa--fa: "\f0a8\f0a8"; } + +.fa-group-arrows-rotate { + --fa: "\e4f6"; + --fa--fa: "\e4f6\e4f6"; } + +.fa-bowl-food { + --fa: "\e4c6"; + --fa--fa: "\e4c6\e4c6"; } + +.fa-candy-cane { + --fa: "\f786"; + --fa--fa: "\f786\f786"; } + +.fa-arrow-down-wide-short { + --fa: "\f160"; + --fa--fa: "\f160\f160"; } + +.fa-sort-amount-asc { + --fa: "\f160"; + --fa--fa: "\f160\f160"; } + +.fa-sort-amount-down { + --fa: "\f160"; + --fa--fa: "\f160\f160"; } + +.fa-cloud-bolt { + --fa: "\f76c"; + --fa--fa: "\f76c\f76c"; } + +.fa-thunderstorm { + --fa: "\f76c"; + --fa--fa: "\f76c\f76c"; } + +.fa-text-slash { + --fa: "\f87d"; + --fa--fa: "\f87d\f87d"; } + +.fa-remove-format { + --fa: "\f87d"; + --fa--fa: "\f87d\f87d"; } + +.fa-face-smile-wink { + --fa: "\f4da"; + --fa--fa: "\f4da\f4da"; } + +.fa-smile-wink { + --fa: "\f4da"; + --fa--fa: "\f4da\f4da"; } + +.fa-file-word { + --fa: "\f1c2"; + --fa--fa: "\f1c2\f1c2"; } + +.fa-file-powerpoint { + --fa: "\f1c4"; + --fa--fa: "\f1c4\f1c4"; } + +.fa-arrows-left-right { + --fa: "\f07e"; + --fa--fa: "\f07e\f07e"; } + +.fa-arrows-h { + --fa: "\f07e"; + --fa--fa: "\f07e\f07e"; } + +.fa-house-lock { + --fa: "\e510"; + --fa--fa: "\e510\e510"; } + +.fa-cloud-arrow-down { + --fa: "\f0ed"; + --fa--fa: "\f0ed\f0ed"; } + +.fa-cloud-download { + --fa: "\f0ed"; + --fa--fa: "\f0ed\f0ed"; } + +.fa-cloud-download-alt { + --fa: "\f0ed"; + --fa--fa: "\f0ed\f0ed"; } + +.fa-children { + --fa: "\e4e1"; + --fa--fa: "\e4e1\e4e1"; } + +.fa-chalkboard { + --fa: "\f51b"; + --fa--fa: "\f51b\f51b"; } + +.fa-blackboard { + --fa: "\f51b"; + --fa--fa: "\f51b\f51b"; } + +.fa-user-large-slash { + --fa: "\f4fa"; + --fa--fa: "\f4fa\f4fa"; } + +.fa-user-alt-slash { + --fa: "\f4fa"; + --fa--fa: "\f4fa\f4fa"; } + +.fa-envelope-open { + --fa: "\f2b6"; + --fa--fa: "\f2b6\f2b6"; } + +.fa-handshake-simple-slash { + --fa: "\e05f"; + --fa--fa: "\e05f\e05f"; } + +.fa-handshake-alt-slash { + --fa: "\e05f"; + --fa--fa: "\e05f\e05f"; } + +.fa-mattress-pillow { + --fa: "\e525"; + --fa--fa: "\e525\e525"; } + +.fa-guarani-sign { + --fa: "\e19a"; + --fa--fa: "\e19a\e19a"; } + +.fa-arrows-rotate { + --fa: "\f021"; + --fa--fa: "\f021\f021"; } + +.fa-refresh { + --fa: "\f021"; + --fa--fa: "\f021\f021"; } + +.fa-sync { + --fa: "\f021"; + --fa--fa: "\f021\f021"; } + +.fa-fire-extinguisher { + --fa: "\f134"; + --fa--fa: "\f134\f134"; } + +.fa-cruzeiro-sign { + --fa: "\e152"; + --fa--fa: "\e152\e152"; } + +.fa-greater-than-equal { + --fa: "\f532"; + --fa--fa: "\f532\f532"; } + +.fa-shield-halved { + --fa: "\f3ed"; + --fa--fa: "\f3ed\f3ed"; } + +.fa-shield-alt { + --fa: "\f3ed"; + --fa--fa: "\f3ed\f3ed"; } + +.fa-book-atlas { + --fa: "\f558"; + --fa--fa: "\f558\f558"; } + +.fa-atlas { + --fa: "\f558"; + --fa--fa: "\f558\f558"; } + +.fa-virus { + --fa: "\e074"; + --fa--fa: "\e074\e074"; } + +.fa-envelope-circle-check { + --fa: "\e4e8"; + --fa--fa: "\e4e8\e4e8"; } + +.fa-layer-group { + --fa: "\f5fd"; + --fa--fa: "\f5fd\f5fd"; } + +.fa-arrows-to-dot { + --fa: "\e4be"; + --fa--fa: "\e4be\e4be"; } + +.fa-archway { + --fa: "\f557"; + --fa--fa: "\f557\f557"; } + +.fa-heart-circle-check { + --fa: "\e4fd"; + --fa--fa: "\e4fd\e4fd"; } + +.fa-house-chimney-crack { + --fa: "\f6f1"; + --fa--fa: "\f6f1\f6f1"; } + +.fa-house-damage { + --fa: "\f6f1"; + --fa--fa: "\f6f1\f6f1"; } + +.fa-file-zipper { + --fa: "\f1c6"; + --fa--fa: "\f1c6\f1c6"; } + +.fa-file-archive { + --fa: "\f1c6"; + --fa--fa: "\f1c6\f1c6"; } + +.fa-square { + --fa: "\f0c8"; + --fa--fa: "\f0c8\f0c8"; } + +.fa-martini-glass-empty { + --fa: "\f000"; + --fa--fa: "\f000\f000"; } + +.fa-glass-martini { + --fa: "\f000"; + --fa--fa: "\f000\f000"; } + +.fa-couch { + --fa: "\f4b8"; + --fa--fa: "\f4b8\f4b8"; } + +.fa-cedi-sign { + --fa: "\e0df"; + --fa--fa: "\e0df\e0df"; } + +.fa-italic { + --fa: "\f033"; + --fa--fa: "\f033\f033"; } + +.fa-table-cells-column-lock { + --fa: "\e678"; + --fa--fa: "\e678\e678"; } + +.fa-church { + --fa: "\f51d"; + --fa--fa: "\f51d\f51d"; } + +.fa-comments-dollar { + --fa: "\f653"; + --fa--fa: "\f653\f653"; } + +.fa-democrat { + --fa: "\f747"; + --fa--fa: "\f747\f747"; } + +.fa-z { + --fa: "\5a"; + --fa--fa: "\5a\5a"; } + +.fa-person-skiing { + --fa: "\f7c9"; + --fa--fa: "\f7c9\f7c9"; } + +.fa-skiing { + --fa: "\f7c9"; + --fa--fa: "\f7c9\f7c9"; } + +.fa-road-lock { + --fa: "\e567"; + --fa--fa: "\e567\e567"; } + +.fa-a { + --fa: "\41"; + --fa--fa: "\41\41"; } + +.fa-temperature-arrow-down { + --fa: "\e03f"; + --fa--fa: "\e03f\e03f"; } + +.fa-temperature-down { + --fa: "\e03f"; + --fa--fa: "\e03f\e03f"; } + +.fa-feather-pointed { + --fa: "\f56b"; + --fa--fa: "\f56b\f56b"; } + +.fa-feather-alt { + --fa: "\f56b"; + --fa--fa: "\f56b\f56b"; } + +.fa-p { + --fa: "\50"; + --fa--fa: "\50\50"; } + +.fa-snowflake { + --fa: "\f2dc"; + --fa--fa: "\f2dc\f2dc"; } + +.fa-newspaper { + --fa: "\f1ea"; + --fa--fa: "\f1ea\f1ea"; } + +.fa-rectangle-ad { + --fa: "\f641"; + --fa--fa: "\f641\f641"; } + +.fa-ad { + --fa: "\f641"; + --fa--fa: "\f641\f641"; } + +.fa-circle-arrow-right { + --fa: "\f0a9"; + --fa--fa: "\f0a9\f0a9"; } + +.fa-arrow-circle-right { + --fa: "\f0a9"; + --fa--fa: "\f0a9\f0a9"; } + +.fa-filter-circle-xmark { + --fa: "\e17b"; + --fa--fa: "\e17b\e17b"; } + +.fa-locust { + --fa: "\e520"; + --fa--fa: "\e520\e520"; } + +.fa-sort { + --fa: "\f0dc"; + --fa--fa: "\f0dc\f0dc"; } + +.fa-unsorted { + --fa: "\f0dc"; + --fa--fa: "\f0dc\f0dc"; } + +.fa-list-ol { + --fa: "\f0cb"; + --fa--fa: "\f0cb\f0cb"; } + +.fa-list-1-2 { + --fa: "\f0cb"; + --fa--fa: "\f0cb\f0cb"; } + +.fa-list-numeric { + --fa: "\f0cb"; + --fa--fa: "\f0cb\f0cb"; } + +.fa-person-dress-burst { + --fa: "\e544"; + --fa--fa: "\e544\e544"; } + +.fa-money-check-dollar { + --fa: "\f53d"; + --fa--fa: "\f53d\f53d"; } + +.fa-money-check-alt { + --fa: "\f53d"; + --fa--fa: "\f53d\f53d"; } + +.fa-vector-square { + --fa: "\f5cb"; + --fa--fa: "\f5cb\f5cb"; } + +.fa-bread-slice { + --fa: "\f7ec"; + --fa--fa: "\f7ec\f7ec"; } + +.fa-language { + --fa: "\f1ab"; + --fa--fa: "\f1ab\f1ab"; } + +.fa-face-kiss-wink-heart { + --fa: "\f598"; + --fa--fa: "\f598\f598"; } + +.fa-kiss-wink-heart { + --fa: "\f598"; + --fa--fa: "\f598\f598"; } + +.fa-filter { + --fa: "\f0b0"; + --fa--fa: "\f0b0\f0b0"; } + +.fa-question { + --fa: "\3f"; + --fa--fa: "\3f\3f"; } + +.fa-file-signature { + --fa: "\f573"; + --fa--fa: "\f573\f573"; } + +.fa-up-down-left-right { + --fa: "\f0b2"; + --fa--fa: "\f0b2\f0b2"; } + +.fa-arrows-alt { + --fa: "\f0b2"; + --fa--fa: "\f0b2\f0b2"; } + +.fa-house-chimney-user { + --fa: "\e065"; + --fa--fa: "\e065\e065"; } + +.fa-hand-holding-heart { + --fa: "\f4be"; + --fa--fa: "\f4be\f4be"; } + +.fa-puzzle-piece { + --fa: "\f12e"; + --fa--fa: "\f12e\f12e"; } + +.fa-money-check { + --fa: "\f53c"; + --fa--fa: "\f53c\f53c"; } + +.fa-star-half-stroke { + --fa: "\f5c0"; + --fa--fa: "\f5c0\f5c0"; } + +.fa-star-half-alt { + --fa: "\f5c0"; + --fa--fa: "\f5c0\f5c0"; } + +.fa-code { + --fa: "\f121"; + --fa--fa: "\f121\f121"; } + +.fa-whiskey-glass { + --fa: "\f7a0"; + --fa--fa: "\f7a0\f7a0"; } + +.fa-glass-whiskey { + --fa: "\f7a0"; + --fa--fa: "\f7a0\f7a0"; } + +.fa-building-circle-exclamation { + --fa: "\e4d3"; + --fa--fa: "\e4d3\e4d3"; } + +.fa-magnifying-glass-chart { + --fa: "\e522"; + --fa--fa: "\e522\e522"; } + +.fa-arrow-up-right-from-square { + --fa: "\f08e"; + --fa--fa: "\f08e\f08e"; } + +.fa-external-link { + --fa: "\f08e"; + --fa--fa: "\f08e\f08e"; } + +.fa-cubes-stacked { + --fa: "\e4e6"; + --fa--fa: "\e4e6\e4e6"; } + +.fa-won-sign { + --fa: "\f159"; + --fa--fa: "\f159\f159"; } + +.fa-krw { + --fa: "\f159"; + --fa--fa: "\f159\f159"; } + +.fa-won { + --fa: "\f159"; + --fa--fa: "\f159\f159"; } + +.fa-virus-covid { + --fa: "\e4a8"; + --fa--fa: "\e4a8\e4a8"; } + +.fa-austral-sign { + --fa: "\e0a9"; + --fa--fa: "\e0a9\e0a9"; } + +.fa-f { + --fa: "\46"; + --fa--fa: "\46\46"; } + +.fa-leaf { + --fa: "\f06c"; + --fa--fa: "\f06c\f06c"; } + +.fa-road { + --fa: "\f018"; + --fa--fa: "\f018\f018"; } + +.fa-taxi { + --fa: "\f1ba"; + --fa--fa: "\f1ba\f1ba"; } + +.fa-cab { + --fa: "\f1ba"; + --fa--fa: "\f1ba\f1ba"; } + +.fa-person-circle-plus { + --fa: "\e541"; + --fa--fa: "\e541\e541"; } + +.fa-chart-pie { + --fa: "\f200"; + --fa--fa: "\f200\f200"; } + +.fa-pie-chart { + --fa: "\f200"; + --fa--fa: "\f200\f200"; } + +.fa-bolt-lightning { + --fa: "\e0b7"; + --fa--fa: "\e0b7\e0b7"; } + +.fa-sack-xmark { + --fa: "\e56a"; + --fa--fa: "\e56a\e56a"; } + +.fa-file-excel { + --fa: "\f1c3"; + --fa--fa: "\f1c3\f1c3"; } + +.fa-file-contract { + --fa: "\f56c"; + --fa--fa: "\f56c\f56c"; } + +.fa-fish-fins { + --fa: "\e4f2"; + --fa--fa: "\e4f2\e4f2"; } + +.fa-building-flag { + --fa: "\e4d5"; + --fa--fa: "\e4d5\e4d5"; } + +.fa-face-grin-beam { + --fa: "\f582"; + --fa--fa: "\f582\f582"; } + +.fa-grin-beam { + --fa: "\f582"; + --fa--fa: "\f582\f582"; } + +.fa-object-ungroup { + --fa: "\f248"; + --fa--fa: "\f248\f248"; } + +.fa-poop { + --fa: "\f619"; + --fa--fa: "\f619\f619"; } + +.fa-location-pin { + --fa: "\f041"; + --fa--fa: "\f041\f041"; } + +.fa-map-marker { + --fa: "\f041"; + --fa--fa: "\f041\f041"; } + +.fa-kaaba { + --fa: "\f66b"; + --fa--fa: "\f66b\f66b"; } + +.fa-toilet-paper { + --fa: "\f71e"; + --fa--fa: "\f71e\f71e"; } + +.fa-helmet-safety { + --fa: "\f807"; + --fa--fa: "\f807\f807"; } + +.fa-hard-hat { + --fa: "\f807"; + --fa--fa: "\f807\f807"; } + +.fa-hat-hard { + --fa: "\f807"; + --fa--fa: "\f807\f807"; } + +.fa-eject { + --fa: "\f052"; + --fa--fa: "\f052\f052"; } + +.fa-circle-right { + --fa: "\f35a"; + --fa--fa: "\f35a\f35a"; } + +.fa-arrow-alt-circle-right { + --fa: "\f35a"; + --fa--fa: "\f35a\f35a"; } + +.fa-plane-circle-check { + --fa: "\e555"; + --fa--fa: "\e555\e555"; } + +.fa-face-rolling-eyes { + --fa: "\f5a5"; + --fa--fa: "\f5a5\f5a5"; } + +.fa-meh-rolling-eyes { + --fa: "\f5a5"; + --fa--fa: "\f5a5\f5a5"; } + +.fa-object-group { + --fa: "\f247"; + --fa--fa: "\f247\f247"; } + +.fa-chart-line { + --fa: "\f201"; + --fa--fa: "\f201\f201"; } + +.fa-line-chart { + --fa: "\f201"; + --fa--fa: "\f201\f201"; } + +.fa-mask-ventilator { + --fa: "\e524"; + --fa--fa: "\e524\e524"; } + +.fa-arrow-right { + --fa: "\f061"; + --fa--fa: "\f061\f061"; } + +.fa-signs-post { + --fa: "\f277"; + --fa--fa: "\f277\f277"; } + +.fa-map-signs { + --fa: "\f277"; + --fa--fa: "\f277\f277"; } + +.fa-cash-register { + --fa: "\f788"; + --fa--fa: "\f788\f788"; } + +.fa-person-circle-question { + --fa: "\e542"; + --fa--fa: "\e542\e542"; } + +.fa-h { + --fa: "\48"; + --fa--fa: "\48\48"; } + +.fa-tarp { + --fa: "\e57b"; + --fa--fa: "\e57b\e57b"; } + +.fa-screwdriver-wrench { + --fa: "\f7d9"; + --fa--fa: "\f7d9\f7d9"; } + +.fa-tools { + --fa: "\f7d9"; + --fa--fa: "\f7d9\f7d9"; } + +.fa-arrows-to-eye { + --fa: "\e4bf"; + --fa--fa: "\e4bf\e4bf"; } + +.fa-plug-circle-bolt { + --fa: "\e55b"; + --fa--fa: "\e55b\e55b"; } + +.fa-heart { + --fa: "\f004"; + --fa--fa: "\f004\f004"; } + +.fa-mars-and-venus { + --fa: "\f224"; + --fa--fa: "\f224\f224"; } + +.fa-house-user { + --fa: "\e1b0"; + --fa--fa: "\e1b0\e1b0"; } + +.fa-home-user { + --fa: "\e1b0"; + --fa--fa: "\e1b0\e1b0"; } + +.fa-dumpster-fire { + --fa: "\f794"; + --fa--fa: "\f794\f794"; } + +.fa-house-crack { + --fa: "\e3b1"; + --fa--fa: "\e3b1\e3b1"; } + +.fa-martini-glass-citrus { + --fa: "\f561"; + --fa--fa: "\f561\f561"; } + +.fa-cocktail { + --fa: "\f561"; + --fa--fa: "\f561\f561"; } + +.fa-face-surprise { + --fa: "\f5c2"; + --fa--fa: "\f5c2\f5c2"; } + +.fa-surprise { + --fa: "\f5c2"; + --fa--fa: "\f5c2\f5c2"; } + +.fa-bottle-water { + --fa: "\e4c5"; + --fa--fa: "\e4c5\e4c5"; } + +.fa-circle-pause { + --fa: "\f28b"; + --fa--fa: "\f28b\f28b"; } + +.fa-pause-circle { + --fa: "\f28b"; + --fa--fa: "\f28b\f28b"; } + +.fa-toilet-paper-slash { + --fa: "\e072"; + --fa--fa: "\e072\e072"; } + +.fa-apple-whole { + --fa: "\f5d1"; + --fa--fa: "\f5d1\f5d1"; } + +.fa-apple-alt { + --fa: "\f5d1"; + --fa--fa: "\f5d1\f5d1"; } + +.fa-kitchen-set { + --fa: "\e51a"; + --fa--fa: "\e51a\e51a"; } + +.fa-r { + --fa: "\52"; + --fa--fa: "\52\52"; } + +.fa-temperature-quarter { + --fa: "\f2ca"; + --fa--fa: "\f2ca\f2ca"; } + +.fa-temperature-1 { + --fa: "\f2ca"; + --fa--fa: "\f2ca\f2ca"; } + +.fa-thermometer-1 { + --fa: "\f2ca"; + --fa--fa: "\f2ca\f2ca"; } + +.fa-thermometer-quarter { + --fa: "\f2ca"; + --fa--fa: "\f2ca\f2ca"; } + +.fa-cube { + --fa: "\f1b2"; + --fa--fa: "\f1b2\f1b2"; } + +.fa-bitcoin-sign { + --fa: "\e0b4"; + --fa--fa: "\e0b4\e0b4"; } + +.fa-shield-dog { + --fa: "\e573"; + --fa--fa: "\e573\e573"; } + +.fa-solar-panel { + --fa: "\f5ba"; + --fa--fa: "\f5ba\f5ba"; } + +.fa-lock-open { + --fa: "\f3c1"; + --fa--fa: "\f3c1\f3c1"; } + +.fa-elevator { + --fa: "\e16d"; + --fa--fa: "\e16d\e16d"; } + +.fa-money-bill-transfer { + --fa: "\e528"; + --fa--fa: "\e528\e528"; } + +.fa-money-bill-trend-up { + --fa: "\e529"; + --fa--fa: "\e529\e529"; } + +.fa-house-flood-water-circle-arrow-right { + --fa: "\e50f"; + --fa--fa: "\e50f\e50f"; } + +.fa-square-poll-horizontal { + --fa: "\f682"; + --fa--fa: "\f682\f682"; } + +.fa-poll-h { + --fa: "\f682"; + --fa--fa: "\f682\f682"; } + +.fa-circle { + --fa: "\f111"; + --fa--fa: "\f111\f111"; } + +.fa-backward-fast { + --fa: "\f049"; + --fa--fa: "\f049\f049"; } + +.fa-fast-backward { + --fa: "\f049"; + --fa--fa: "\f049\f049"; } + +.fa-recycle { + --fa: "\f1b8"; + --fa--fa: "\f1b8\f1b8"; } + +.fa-user-astronaut { + --fa: "\f4fb"; + --fa--fa: "\f4fb\f4fb"; } + +.fa-plane-slash { + --fa: "\e069"; + --fa--fa: "\e069\e069"; } + +.fa-trademark { + --fa: "\f25c"; + --fa--fa: "\f25c\f25c"; } + +.fa-basketball { + --fa: "\f434"; + --fa--fa: "\f434\f434"; } + +.fa-basketball-ball { + --fa: "\f434"; + --fa--fa: "\f434\f434"; } + +.fa-satellite-dish { + --fa: "\f7c0"; + --fa--fa: "\f7c0\f7c0"; } + +.fa-circle-up { + --fa: "\f35b"; + --fa--fa: "\f35b\f35b"; } + +.fa-arrow-alt-circle-up { + --fa: "\f35b"; + --fa--fa: "\f35b\f35b"; } + +.fa-mobile-screen-button { + --fa: "\f3cd"; + --fa--fa: "\f3cd\f3cd"; } + +.fa-mobile-alt { + --fa: "\f3cd"; + --fa--fa: "\f3cd\f3cd"; } + +.fa-volume-high { + --fa: "\f028"; + --fa--fa: "\f028\f028"; } + +.fa-volume-up { + --fa: "\f028"; + --fa--fa: "\f028\f028"; } + +.fa-users-rays { + --fa: "\e593"; + --fa--fa: "\e593\e593"; } + +.fa-wallet { + --fa: "\f555"; + --fa--fa: "\f555\f555"; } + +.fa-clipboard-check { + --fa: "\f46c"; + --fa--fa: "\f46c\f46c"; } + +.fa-file-audio { + --fa: "\f1c7"; + --fa--fa: "\f1c7\f1c7"; } + +.fa-burger { + --fa: "\f805"; + --fa--fa: "\f805\f805"; } + +.fa-hamburger { + --fa: "\f805"; + --fa--fa: "\f805\f805"; } + +.fa-wrench { + --fa: "\f0ad"; + --fa--fa: "\f0ad\f0ad"; } + +.fa-bugs { + --fa: "\e4d0"; + --fa--fa: "\e4d0\e4d0"; } + +.fa-rupee-sign { + --fa: "\f156"; + --fa--fa: "\f156\f156"; } + +.fa-rupee { + --fa: "\f156"; + --fa--fa: "\f156\f156"; } + +.fa-file-image { + --fa: "\f1c5"; + --fa--fa: "\f1c5\f1c5"; } + +.fa-circle-question { + --fa: "\f059"; + --fa--fa: "\f059\f059"; } + +.fa-question-circle { + --fa: "\f059"; + --fa--fa: "\f059\f059"; } + +.fa-plane-departure { + --fa: "\f5b0"; + --fa--fa: "\f5b0\f5b0"; } + +.fa-handshake-slash { + --fa: "\e060"; + --fa--fa: "\e060\e060"; } + +.fa-book-bookmark { + --fa: "\e0bb"; + --fa--fa: "\e0bb\e0bb"; } + +.fa-code-branch { + --fa: "\f126"; + --fa--fa: "\f126\f126"; } + +.fa-hat-cowboy { + --fa: "\f8c0"; + --fa--fa: "\f8c0\f8c0"; } + +.fa-bridge { + --fa: "\e4c8"; + --fa--fa: "\e4c8\e4c8"; } + +.fa-phone-flip { + --fa: "\f879"; + --fa--fa: "\f879\f879"; } + +.fa-phone-alt { + --fa: "\f879"; + --fa--fa: "\f879\f879"; } + +.fa-truck-front { + --fa: "\e2b7"; + --fa--fa: "\e2b7\e2b7"; } + +.fa-cat { + --fa: "\f6be"; + --fa--fa: "\f6be\f6be"; } + +.fa-anchor-circle-exclamation { + --fa: "\e4ab"; + --fa--fa: "\e4ab\e4ab"; } + +.fa-truck-field { + --fa: "\e58d"; + --fa--fa: "\e58d\e58d"; } + +.fa-route { + --fa: "\f4d7"; + --fa--fa: "\f4d7\f4d7"; } + +.fa-clipboard-question { + --fa: "\e4e3"; + --fa--fa: "\e4e3\e4e3"; } + +.fa-panorama { + --fa: "\e209"; + --fa--fa: "\e209\e209"; } + +.fa-comment-medical { + --fa: "\f7f5"; + --fa--fa: "\f7f5\f7f5"; } + +.fa-teeth-open { + --fa: "\f62f"; + --fa--fa: "\f62f\f62f"; } + +.fa-file-circle-minus { + --fa: "\e4ed"; + --fa--fa: "\e4ed\e4ed"; } + +.fa-tags { + --fa: "\f02c"; + --fa--fa: "\f02c\f02c"; } + +.fa-wine-glass { + --fa: "\f4e3"; + --fa--fa: "\f4e3\f4e3"; } + +.fa-forward-fast { + --fa: "\f050"; + --fa--fa: "\f050\f050"; } + +.fa-fast-forward { + --fa: "\f050"; + --fa--fa: "\f050\f050"; } + +.fa-face-meh-blank { + --fa: "\f5a4"; + --fa--fa: "\f5a4\f5a4"; } + +.fa-meh-blank { + --fa: "\f5a4"; + --fa--fa: "\f5a4\f5a4"; } + +.fa-square-parking { + --fa: "\f540"; + --fa--fa: "\f540\f540"; } + +.fa-parking { + --fa: "\f540"; + --fa--fa: "\f540\f540"; } + +.fa-house-signal { + --fa: "\e012"; + --fa--fa: "\e012\e012"; } + +.fa-bars-progress { + --fa: "\f828"; + --fa--fa: "\f828\f828"; } + +.fa-tasks-alt { + --fa: "\f828"; + --fa--fa: "\f828\f828"; } + +.fa-faucet-drip { + --fa: "\e006"; + --fa--fa: "\e006\e006"; } + +.fa-cart-flatbed { + --fa: "\f474"; + --fa--fa: "\f474\f474"; } + +.fa-dolly-flatbed { + --fa: "\f474"; + --fa--fa: "\f474\f474"; } + +.fa-ban-smoking { + --fa: "\f54d"; + --fa--fa: "\f54d\f54d"; } + +.fa-smoking-ban { + --fa: "\f54d"; + --fa--fa: "\f54d\f54d"; } + +.fa-terminal { + --fa: "\f120"; + --fa--fa: "\f120\f120"; } + +.fa-mobile-button { + --fa: "\f10b"; + --fa--fa: "\f10b\f10b"; } + +.fa-house-medical-flag { + --fa: "\e514"; + --fa--fa: "\e514\e514"; } + +.fa-basket-shopping { + --fa: "\f291"; + --fa--fa: "\f291\f291"; } + +.fa-shopping-basket { + --fa: "\f291"; + --fa--fa: "\f291\f291"; } + +.fa-tape { + --fa: "\f4db"; + --fa--fa: "\f4db\f4db"; } + +.fa-bus-simple { + --fa: "\f55e"; + --fa--fa: "\f55e\f55e"; } + +.fa-bus-alt { + --fa: "\f55e"; + --fa--fa: "\f55e\f55e"; } + +.fa-eye { + --fa: "\f06e"; + --fa--fa: "\f06e\f06e"; } + +.fa-face-sad-cry { + --fa: "\f5b3"; + --fa--fa: "\f5b3\f5b3"; } + +.fa-sad-cry { + --fa: "\f5b3"; + --fa--fa: "\f5b3\f5b3"; } + +.fa-audio-description { + --fa: "\f29e"; + --fa--fa: "\f29e\f29e"; } + +.fa-person-military-to-person { + --fa: "\e54c"; + --fa--fa: "\e54c\e54c"; } + +.fa-file-shield { + --fa: "\e4f0"; + --fa--fa: "\e4f0\e4f0"; } + +.fa-user-slash { + --fa: "\f506"; + --fa--fa: "\f506\f506"; } + +.fa-pen { + --fa: "\f304"; + --fa--fa: "\f304\f304"; } + +.fa-tower-observation { + --fa: "\e586"; + --fa--fa: "\e586\e586"; } + +.fa-file-code { + --fa: "\f1c9"; + --fa--fa: "\f1c9\f1c9"; } + +.fa-signal { + --fa: "\f012"; + --fa--fa: "\f012\f012"; } + +.fa-signal-5 { + --fa: "\f012"; + --fa--fa: "\f012\f012"; } + +.fa-signal-perfect { + --fa: "\f012"; + --fa--fa: "\f012\f012"; } + +.fa-bus { + --fa: "\f207"; + --fa--fa: "\f207\f207"; } + +.fa-heart-circle-xmark { + --fa: "\e501"; + --fa--fa: "\e501\e501"; } + +.fa-house-chimney { + --fa: "\e3af"; + --fa--fa: "\e3af\e3af"; } + +.fa-home-lg { + --fa: "\e3af"; + --fa--fa: "\e3af\e3af"; } + +.fa-window-maximize { + --fa: "\f2d0"; + --fa--fa: "\f2d0\f2d0"; } + +.fa-face-frown { + --fa: "\f119"; + --fa--fa: "\f119\f119"; } + +.fa-frown { + --fa: "\f119"; + --fa--fa: "\f119\f119"; } + +.fa-prescription { + --fa: "\f5b1"; + --fa--fa: "\f5b1\f5b1"; } + +.fa-shop { + --fa: "\f54f"; + --fa--fa: "\f54f\f54f"; } + +.fa-store-alt { + --fa: "\f54f"; + --fa--fa: "\f54f\f54f"; } + +.fa-floppy-disk { + --fa: "\f0c7"; + --fa--fa: "\f0c7\f0c7"; } + +.fa-save { + --fa: "\f0c7"; + --fa--fa: "\f0c7\f0c7"; } + +.fa-vihara { + --fa: "\f6a7"; + --fa--fa: "\f6a7\f6a7"; } + +.fa-scale-unbalanced { + --fa: "\f515"; + --fa--fa: "\f515\f515"; } + +.fa-balance-scale-left { + --fa: "\f515"; + --fa--fa: "\f515\f515"; } + +.fa-sort-up { + --fa: "\f0de"; + --fa--fa: "\f0de\f0de"; } + +.fa-sort-asc { + --fa: "\f0de"; + --fa--fa: "\f0de\f0de"; } + +.fa-comment-dots { + --fa: "\f4ad"; + --fa--fa: "\f4ad\f4ad"; } + +.fa-commenting { + --fa: "\f4ad"; + --fa--fa: "\f4ad\f4ad"; } + +.fa-plant-wilt { + --fa: "\e5aa"; + --fa--fa: "\e5aa\e5aa"; } + +.fa-diamond { + --fa: "\f219"; + --fa--fa: "\f219\f219"; } + +.fa-face-grin-squint { + --fa: "\f585"; + --fa--fa: "\f585\f585"; } + +.fa-grin-squint { + --fa: "\f585"; + --fa--fa: "\f585\f585"; } + +.fa-hand-holding-dollar { + --fa: "\f4c0"; + --fa--fa: "\f4c0\f4c0"; } + +.fa-hand-holding-usd { + --fa: "\f4c0"; + --fa--fa: "\f4c0\f4c0"; } + +.fa-chart-diagram { + --fa: "\e695"; + --fa--fa: "\e695\e695"; } + +.fa-bacterium { + --fa: "\e05a"; + --fa--fa: "\e05a\e05a"; } + +.fa-hand-pointer { + --fa: "\f25a"; + --fa--fa: "\f25a\f25a"; } + +.fa-drum-steelpan { + --fa: "\f56a"; + --fa--fa: "\f56a\f56a"; } + +.fa-hand-scissors { + --fa: "\f257"; + --fa--fa: "\f257\f257"; } + +.fa-hands-praying { + --fa: "\f684"; + --fa--fa: "\f684\f684"; } + +.fa-praying-hands { + --fa: "\f684"; + --fa--fa: "\f684\f684"; } + +.fa-arrow-rotate-right { + --fa: "\f01e"; + --fa--fa: "\f01e\f01e"; } + +.fa-arrow-right-rotate { + --fa: "\f01e"; + --fa--fa: "\f01e\f01e"; } + +.fa-arrow-rotate-forward { + --fa: "\f01e"; + --fa--fa: "\f01e\f01e"; } + +.fa-redo { + --fa: "\f01e"; + --fa--fa: "\f01e\f01e"; } + +.fa-biohazard { + --fa: "\f780"; + --fa--fa: "\f780\f780"; } + +.fa-location-crosshairs { + --fa: "\f601"; + --fa--fa: "\f601\f601"; } + +.fa-location { + --fa: "\f601"; + --fa--fa: "\f601\f601"; } + +.fa-mars-double { + --fa: "\f227"; + --fa--fa: "\f227\f227"; } + +.fa-child-dress { + --fa: "\e59c"; + --fa--fa: "\e59c\e59c"; } + +.fa-users-between-lines { + --fa: "\e591"; + --fa--fa: "\e591\e591"; } + +.fa-lungs-virus { + --fa: "\e067"; + --fa--fa: "\e067\e067"; } + +.fa-face-grin-tears { + --fa: "\f588"; + --fa--fa: "\f588\f588"; } + +.fa-grin-tears { + --fa: "\f588"; + --fa--fa: "\f588\f588"; } + +.fa-phone { + --fa: "\f095"; + --fa--fa: "\f095\f095"; } + +.fa-calendar-xmark { + --fa: "\f273"; + --fa--fa: "\f273\f273"; } + +.fa-calendar-times { + --fa: "\f273"; + --fa--fa: "\f273\f273"; } + +.fa-child-reaching { + --fa: "\e59d"; + --fa--fa: "\e59d\e59d"; } + +.fa-head-side-virus { + --fa: "\e064"; + --fa--fa: "\e064\e064"; } + +.fa-user-gear { + --fa: "\f4fe"; + --fa--fa: "\f4fe\f4fe"; } + +.fa-user-cog { + --fa: "\f4fe"; + --fa--fa: "\f4fe\f4fe"; } + +.fa-arrow-up-1-9 { + --fa: "\f163"; + --fa--fa: "\f163\f163"; } + +.fa-sort-numeric-up { + --fa: "\f163"; + --fa--fa: "\f163\f163"; } + +.fa-door-closed { + --fa: "\f52a"; + --fa--fa: "\f52a\f52a"; } + +.fa-shield-virus { + --fa: "\e06c"; + --fa--fa: "\e06c\e06c"; } + +.fa-dice-six { + --fa: "\f526"; + --fa--fa: "\f526\f526"; } + +.fa-mosquito-net { + --fa: "\e52c"; + --fa--fa: "\e52c\e52c"; } + +.fa-file-fragment { + --fa: "\e697"; + --fa--fa: "\e697\e697"; } + +.fa-bridge-water { + --fa: "\e4ce"; + --fa--fa: "\e4ce\e4ce"; } + +.fa-person-booth { + --fa: "\f756"; + --fa--fa: "\f756\f756"; } + +.fa-text-width { + --fa: "\f035"; + --fa--fa: "\f035\f035"; } + +.fa-hat-wizard { + --fa: "\f6e8"; + --fa--fa: "\f6e8\f6e8"; } + +.fa-pen-fancy { + --fa: "\f5ac"; + --fa--fa: "\f5ac\f5ac"; } + +.fa-person-digging { + --fa: "\f85e"; + --fa--fa: "\f85e\f85e"; } + +.fa-digging { + --fa: "\f85e"; + --fa--fa: "\f85e\f85e"; } + +.fa-trash { + --fa: "\f1f8"; + --fa--fa: "\f1f8\f1f8"; } + +.fa-gauge-simple { + --fa: "\f629"; + --fa--fa: "\f629\f629"; } + +.fa-gauge-simple-med { + --fa: "\f629"; + --fa--fa: "\f629\f629"; } + +.fa-tachometer-average { + --fa: "\f629"; + --fa--fa: "\f629\f629"; } + +.fa-book-medical { + --fa: "\f7e6"; + --fa--fa: "\f7e6\f7e6"; } + +.fa-poo { + --fa: "\f2fe"; + --fa--fa: "\f2fe\f2fe"; } + +.fa-quote-right { + --fa: "\f10e"; + --fa--fa: "\f10e\f10e"; } + +.fa-quote-right-alt { + --fa: "\f10e"; + --fa--fa: "\f10e\f10e"; } + +.fa-shirt { + --fa: "\f553"; + --fa--fa: "\f553\f553"; } + +.fa-t-shirt { + --fa: "\f553"; + --fa--fa: "\f553\f553"; } + +.fa-tshirt { + --fa: "\f553"; + --fa--fa: "\f553\f553"; } + +.fa-cubes { + --fa: "\f1b3"; + --fa--fa: "\f1b3\f1b3"; } + +.fa-divide { + --fa: "\f529"; + --fa--fa: "\f529\f529"; } + +.fa-tenge-sign { + --fa: "\f7d7"; + --fa--fa: "\f7d7\f7d7"; } + +.fa-tenge { + --fa: "\f7d7"; + --fa--fa: "\f7d7\f7d7"; } + +.fa-headphones { + --fa: "\f025"; + --fa--fa: "\f025\f025"; } + +.fa-hands-holding { + --fa: "\f4c2"; + --fa--fa: "\f4c2\f4c2"; } + +.fa-hands-clapping { + --fa: "\e1a8"; + --fa--fa: "\e1a8\e1a8"; } + +.fa-republican { + --fa: "\f75e"; + --fa--fa: "\f75e\f75e"; } + +.fa-arrow-left { + --fa: "\f060"; + --fa--fa: "\f060\f060"; } + +.fa-person-circle-xmark { + --fa: "\e543"; + --fa--fa: "\e543\e543"; } + +.fa-ruler { + --fa: "\f545"; + --fa--fa: "\f545\f545"; } + +.fa-align-left { + --fa: "\f036"; + --fa--fa: "\f036\f036"; } + +.fa-dice-d6 { + --fa: "\f6d1"; + --fa--fa: "\f6d1\f6d1"; } + +.fa-restroom { + --fa: "\f7bd"; + --fa--fa: "\f7bd\f7bd"; } + +.fa-j { + --fa: "\4a"; + --fa--fa: "\4a\4a"; } + +.fa-users-viewfinder { + --fa: "\e595"; + --fa--fa: "\e595\e595"; } + +.fa-file-video { + --fa: "\f1c8"; + --fa--fa: "\f1c8\f1c8"; } + +.fa-up-right-from-square { + --fa: "\f35d"; + --fa--fa: "\f35d\f35d"; } + +.fa-external-link-alt { + --fa: "\f35d"; + --fa--fa: "\f35d\f35d"; } + +.fa-table-cells { + --fa: "\f00a"; + --fa--fa: "\f00a\f00a"; } + +.fa-th { + --fa: "\f00a"; + --fa--fa: "\f00a\f00a"; } + +.fa-file-pdf { + --fa: "\f1c1"; + --fa--fa: "\f1c1\f1c1"; } + +.fa-book-bible { + --fa: "\f647"; + --fa--fa: "\f647\f647"; } + +.fa-bible { + --fa: "\f647"; + --fa--fa: "\f647\f647"; } + +.fa-o { + --fa: "\4f"; + --fa--fa: "\4f\4f"; } + +.fa-suitcase-medical { + --fa: "\f0fa"; + --fa--fa: "\f0fa\f0fa"; } + +.fa-medkit { + --fa: "\f0fa"; + --fa--fa: "\f0fa\f0fa"; } + +.fa-user-secret { + --fa: "\f21b"; + --fa--fa: "\f21b\f21b"; } + +.fa-otter { + --fa: "\f700"; + --fa--fa: "\f700\f700"; } + +.fa-person-dress { + --fa: "\f182"; + --fa--fa: "\f182\f182"; } + +.fa-female { + --fa: "\f182"; + --fa--fa: "\f182\f182"; } + +.fa-comment-dollar { + --fa: "\f651"; + --fa--fa: "\f651\f651"; } + +.fa-business-time { + --fa: "\f64a"; + --fa--fa: "\f64a\f64a"; } + +.fa-briefcase-clock { + --fa: "\f64a"; + --fa--fa: "\f64a\f64a"; } + +.fa-table-cells-large { + --fa: "\f009"; + --fa--fa: "\f009\f009"; } + +.fa-th-large { + --fa: "\f009"; + --fa--fa: "\f009\f009"; } + +.fa-book-tanakh { + --fa: "\f827"; + --fa--fa: "\f827\f827"; } + +.fa-tanakh { + --fa: "\f827"; + --fa--fa: "\f827\f827"; } + +.fa-phone-volume { + --fa: "\f2a0"; + --fa--fa: "\f2a0\f2a0"; } + +.fa-volume-control-phone { + --fa: "\f2a0"; + --fa--fa: "\f2a0\f2a0"; } + +.fa-hat-cowboy-side { + --fa: "\f8c1"; + --fa--fa: "\f8c1\f8c1"; } + +.fa-clipboard-user { + --fa: "\f7f3"; + --fa--fa: "\f7f3\f7f3"; } + +.fa-child { + --fa: "\f1ae"; + --fa--fa: "\f1ae\f1ae"; } + +.fa-lira-sign { + --fa: "\f195"; + --fa--fa: "\f195\f195"; } + +.fa-satellite { + --fa: "\f7bf"; + --fa--fa: "\f7bf\f7bf"; } + +.fa-plane-lock { + --fa: "\e558"; + --fa--fa: "\e558\e558"; } + +.fa-tag { + --fa: "\f02b"; + --fa--fa: "\f02b\f02b"; } + +.fa-comment { + --fa: "\f075"; + --fa--fa: "\f075\f075"; } + +.fa-cake-candles { + --fa: "\f1fd"; + --fa--fa: "\f1fd\f1fd"; } + +.fa-birthday-cake { + --fa: "\f1fd"; + --fa--fa: "\f1fd\f1fd"; } + +.fa-cake { + --fa: "\f1fd"; + --fa--fa: "\f1fd\f1fd"; } + +.fa-envelope { + --fa: "\f0e0"; + --fa--fa: "\f0e0\f0e0"; } + +.fa-angles-up { + --fa: "\f102"; + --fa--fa: "\f102\f102"; } + +.fa-angle-double-up { + --fa: "\f102"; + --fa--fa: "\f102\f102"; } + +.fa-paperclip { + --fa: "\f0c6"; + --fa--fa: "\f0c6\f0c6"; } + +.fa-arrow-right-to-city { + --fa: "\e4b3"; + --fa--fa: "\e4b3\e4b3"; } + +.fa-ribbon { + --fa: "\f4d6"; + --fa--fa: "\f4d6\f4d6"; } + +.fa-lungs { + --fa: "\f604"; + --fa--fa: "\f604\f604"; } + +.fa-arrow-up-9-1 { + --fa: "\f887"; + --fa--fa: "\f887\f887"; } + +.fa-sort-numeric-up-alt { + --fa: "\f887"; + --fa--fa: "\f887\f887"; } + +.fa-litecoin-sign { + --fa: "\e1d3"; + --fa--fa: "\e1d3\e1d3"; } + +.fa-border-none { + --fa: "\f850"; + --fa--fa: "\f850\f850"; } + +.fa-circle-nodes { + --fa: "\e4e2"; + --fa--fa: "\e4e2\e4e2"; } + +.fa-parachute-box { + --fa: "\f4cd"; + --fa--fa: "\f4cd\f4cd"; } + +.fa-indent { + --fa: "\f03c"; + --fa--fa: "\f03c\f03c"; } + +.fa-truck-field-un { + --fa: "\e58e"; + --fa--fa: "\e58e\e58e"; } + +.fa-hourglass { + --fa: "\f254"; + --fa--fa: "\f254\f254"; } + +.fa-hourglass-empty { + --fa: "\f254"; + --fa--fa: "\f254\f254"; } + +.fa-mountain { + --fa: "\f6fc"; + --fa--fa: "\f6fc\f6fc"; } + +.fa-user-doctor { + --fa: "\f0f0"; + --fa--fa: "\f0f0\f0f0"; } + +.fa-user-md { + --fa: "\f0f0"; + --fa--fa: "\f0f0\f0f0"; } + +.fa-circle-info { + --fa: "\f05a"; + --fa--fa: "\f05a\f05a"; } + +.fa-info-circle { + --fa: "\f05a"; + --fa--fa: "\f05a\f05a"; } + +.fa-cloud-meatball { + --fa: "\f73b"; + --fa--fa: "\f73b\f73b"; } + +.fa-camera { + --fa: "\f030"; + --fa--fa: "\f030\f030"; } + +.fa-camera-alt { + --fa: "\f030"; + --fa--fa: "\f030\f030"; } + +.fa-square-virus { + --fa: "\e578"; + --fa--fa: "\e578\e578"; } + +.fa-meteor { + --fa: "\f753"; + --fa--fa: "\f753\f753"; } + +.fa-car-on { + --fa: "\e4dd"; + --fa--fa: "\e4dd\e4dd"; } + +.fa-sleigh { + --fa: "\f7cc"; + --fa--fa: "\f7cc\f7cc"; } + +.fa-arrow-down-1-9 { + --fa: "\f162"; + --fa--fa: "\f162\f162"; } + +.fa-sort-numeric-asc { + --fa: "\f162"; + --fa--fa: "\f162\f162"; } + +.fa-sort-numeric-down { + --fa: "\f162"; + --fa--fa: "\f162\f162"; } + +.fa-hand-holding-droplet { + --fa: "\f4c1"; + --fa--fa: "\f4c1\f4c1"; } + +.fa-hand-holding-water { + --fa: "\f4c1"; + --fa--fa: "\f4c1\f4c1"; } + +.fa-water { + --fa: "\f773"; + --fa--fa: "\f773\f773"; } + +.fa-calendar-check { + --fa: "\f274"; + --fa--fa: "\f274\f274"; } + +.fa-braille { + --fa: "\f2a1"; + --fa--fa: "\f2a1\f2a1"; } + +.fa-prescription-bottle-medical { + --fa: "\f486"; + --fa--fa: "\f486\f486"; } + +.fa-prescription-bottle-alt { + --fa: "\f486"; + --fa--fa: "\f486\f486"; } + +.fa-landmark { + --fa: "\f66f"; + --fa--fa: "\f66f\f66f"; } + +.fa-truck { + --fa: "\f0d1"; + --fa--fa: "\f0d1\f0d1"; } + +.fa-crosshairs { + --fa: "\f05b"; + --fa--fa: "\f05b\f05b"; } + +.fa-person-cane { + --fa: "\e53c"; + --fa--fa: "\e53c\e53c"; } + +.fa-tent { + --fa: "\e57d"; + --fa--fa: "\e57d\e57d"; } + +.fa-vest-patches { + --fa: "\e086"; + --fa--fa: "\e086\e086"; } + +.fa-check-double { + --fa: "\f560"; + --fa--fa: "\f560\f560"; } + +.fa-arrow-down-a-z { + --fa: "\f15d"; + --fa--fa: "\f15d\f15d"; } + +.fa-sort-alpha-asc { + --fa: "\f15d"; + --fa--fa: "\f15d\f15d"; } + +.fa-sort-alpha-down { + --fa: "\f15d"; + --fa--fa: "\f15d\f15d"; } + +.fa-money-bill-wheat { + --fa: "\e52a"; + --fa--fa: "\e52a\e52a"; } + +.fa-cookie { + --fa: "\f563"; + --fa--fa: "\f563\f563"; } + +.fa-arrow-rotate-left { + --fa: "\f0e2"; + --fa--fa: "\f0e2\f0e2"; } + +.fa-arrow-left-rotate { + --fa: "\f0e2"; + --fa--fa: "\f0e2\f0e2"; } + +.fa-arrow-rotate-back { + --fa: "\f0e2"; + --fa--fa: "\f0e2\f0e2"; } + +.fa-arrow-rotate-backward { + --fa: "\f0e2"; + --fa--fa: "\f0e2\f0e2"; } + +.fa-undo { + --fa: "\f0e2"; + --fa--fa: "\f0e2\f0e2"; } + +.fa-hard-drive { + --fa: "\f0a0"; + --fa--fa: "\f0a0\f0a0"; } + +.fa-hdd { + --fa: "\f0a0"; + --fa--fa: "\f0a0\f0a0"; } + +.fa-face-grin-squint-tears { + --fa: "\f586"; + --fa--fa: "\f586\f586"; } + +.fa-grin-squint-tears { + --fa: "\f586"; + --fa--fa: "\f586\f586"; } + +.fa-dumbbell { + --fa: "\f44b"; + --fa--fa: "\f44b\f44b"; } + +.fa-rectangle-list { + --fa: "\f022"; + --fa--fa: "\f022\f022"; } + +.fa-list-alt { + --fa: "\f022"; + --fa--fa: "\f022\f022"; } + +.fa-tarp-droplet { + --fa: "\e57c"; + --fa--fa: "\e57c\e57c"; } + +.fa-house-medical-circle-check { + --fa: "\e511"; + --fa--fa: "\e511\e511"; } + +.fa-person-skiing-nordic { + --fa: "\f7ca"; + --fa--fa: "\f7ca\f7ca"; } + +.fa-skiing-nordic { + --fa: "\f7ca"; + --fa--fa: "\f7ca\f7ca"; } + +.fa-calendar-plus { + --fa: "\f271"; + --fa--fa: "\f271\f271"; } + +.fa-plane-arrival { + --fa: "\f5af"; + --fa--fa: "\f5af\f5af"; } + +.fa-circle-left { + --fa: "\f359"; + --fa--fa: "\f359\f359"; } + +.fa-arrow-alt-circle-left { + --fa: "\f359"; + --fa--fa: "\f359\f359"; } + +.fa-train-subway { + --fa: "\f239"; + --fa--fa: "\f239\f239"; } + +.fa-subway { + --fa: "\f239"; + --fa--fa: "\f239\f239"; } + +.fa-chart-gantt { + --fa: "\e0e4"; + --fa--fa: "\e0e4\e0e4"; } + +.fa-indian-rupee-sign { + --fa: "\e1bc"; + --fa--fa: "\e1bc\e1bc"; } + +.fa-indian-rupee { + --fa: "\e1bc"; + --fa--fa: "\e1bc\e1bc"; } + +.fa-inr { + --fa: "\e1bc"; + --fa--fa: "\e1bc\e1bc"; } + +.fa-crop-simple { + --fa: "\f565"; + --fa--fa: "\f565\f565"; } + +.fa-crop-alt { + --fa: "\f565"; + --fa--fa: "\f565\f565"; } + +.fa-money-bill-1 { + --fa: "\f3d1"; + --fa--fa: "\f3d1\f3d1"; } + +.fa-money-bill-alt { + --fa: "\f3d1"; + --fa--fa: "\f3d1\f3d1"; } + +.fa-left-long { + --fa: "\f30a"; + --fa--fa: "\f30a\f30a"; } + +.fa-long-arrow-alt-left { + --fa: "\f30a"; + --fa--fa: "\f30a\f30a"; } + +.fa-dna { + --fa: "\f471"; + --fa--fa: "\f471\f471"; } + +.fa-virus-slash { + --fa: "\e075"; + --fa--fa: "\e075\e075"; } + +.fa-minus { + --fa: "\f068"; + --fa--fa: "\f068\f068"; } + +.fa-subtract { + --fa: "\f068"; + --fa--fa: "\f068\f068"; } + +.fa-chess { + --fa: "\f439"; + --fa--fa: "\f439\f439"; } + +.fa-arrow-left-long { + --fa: "\f177"; + --fa--fa: "\f177\f177"; } + +.fa-long-arrow-left { + --fa: "\f177"; + --fa--fa: "\f177\f177"; } + +.fa-plug-circle-check { + --fa: "\e55c"; + --fa--fa: "\e55c\e55c"; } + +.fa-street-view { + --fa: "\f21d"; + --fa--fa: "\f21d\f21d"; } + +.fa-franc-sign { + --fa: "\e18f"; + --fa--fa: "\e18f\e18f"; } + +.fa-volume-off { + --fa: "\f026"; + --fa--fa: "\f026\f026"; } + +.fa-hands-asl-interpreting { + --fa: "\f2a3"; + --fa--fa: "\f2a3\f2a3"; } + +.fa-american-sign-language-interpreting { + --fa: "\f2a3"; + --fa--fa: "\f2a3\f2a3"; } + +.fa-asl-interpreting { + --fa: "\f2a3"; + --fa--fa: "\f2a3\f2a3"; } + +.fa-hands-american-sign-language-interpreting { + --fa: "\f2a3"; + --fa--fa: "\f2a3\f2a3"; } + +.fa-gear { + --fa: "\f013"; + --fa--fa: "\f013\f013"; } + +.fa-cog { + --fa: "\f013"; + --fa--fa: "\f013\f013"; } + +.fa-droplet-slash { + --fa: "\f5c7"; + --fa--fa: "\f5c7\f5c7"; } + +.fa-tint-slash { + --fa: "\f5c7"; + --fa--fa: "\f5c7\f5c7"; } + +.fa-mosque { + --fa: "\f678"; + --fa--fa: "\f678\f678"; } + +.fa-mosquito { + --fa: "\e52b"; + --fa--fa: "\e52b\e52b"; } + +.fa-star-of-david { + --fa: "\f69a"; + --fa--fa: "\f69a\f69a"; } + +.fa-person-military-rifle { + --fa: "\e54b"; + --fa--fa: "\e54b\e54b"; } + +.fa-cart-shopping { + --fa: "\f07a"; + --fa--fa: "\f07a\f07a"; } + +.fa-shopping-cart { + --fa: "\f07a"; + --fa--fa: "\f07a\f07a"; } + +.fa-vials { + --fa: "\f493"; + --fa--fa: "\f493\f493"; } + +.fa-plug-circle-plus { + --fa: "\e55f"; + --fa--fa: "\e55f\e55f"; } + +.fa-place-of-worship { + --fa: "\f67f"; + --fa--fa: "\f67f\f67f"; } + +.fa-grip-vertical { + --fa: "\f58e"; + --fa--fa: "\f58e\f58e"; } + +.fa-hexagon-nodes { + --fa: "\e699"; + --fa--fa: "\e699\e699"; } + +.fa-arrow-turn-up { + --fa: "\f148"; + --fa--fa: "\f148\f148"; } + +.fa-level-up { + --fa: "\f148"; + --fa--fa: "\f148\f148"; } + +.fa-u { + --fa: "\55"; + --fa--fa: "\55\55"; } + +.fa-square-root-variable { + --fa: "\f698"; + --fa--fa: "\f698\f698"; } + +.fa-square-root-alt { + --fa: "\f698"; + --fa--fa: "\f698\f698"; } + +.fa-clock { + --fa: "\f017"; + --fa--fa: "\f017\f017"; } + +.fa-clock-four { + --fa: "\f017"; + --fa--fa: "\f017\f017"; } + +.fa-backward-step { + --fa: "\f048"; + --fa--fa: "\f048\f048"; } + +.fa-step-backward { + --fa: "\f048"; + --fa--fa: "\f048\f048"; } + +.fa-pallet { + --fa: "\f482"; + --fa--fa: "\f482\f482"; } + +.fa-faucet { + --fa: "\e005"; + --fa--fa: "\e005\e005"; } + +.fa-baseball-bat-ball { + --fa: "\f432"; + --fa--fa: "\f432\f432"; } + +.fa-s { + --fa: "\53"; + --fa--fa: "\53\53"; } + +.fa-timeline { + --fa: "\e29c"; + --fa--fa: "\e29c\e29c"; } + +.fa-keyboard { + --fa: "\f11c"; + --fa--fa: "\f11c\f11c"; } + +.fa-caret-down { + --fa: "\f0d7"; + --fa--fa: "\f0d7\f0d7"; } + +.fa-house-chimney-medical { + --fa: "\f7f2"; + --fa--fa: "\f7f2\f7f2"; } + +.fa-clinic-medical { + --fa: "\f7f2"; + --fa--fa: "\f7f2\f7f2"; } + +.fa-temperature-three-quarters { + --fa: "\f2c8"; + --fa--fa: "\f2c8\f2c8"; } + +.fa-temperature-3 { + --fa: "\f2c8"; + --fa--fa: "\f2c8\f2c8"; } + +.fa-thermometer-3 { + --fa: "\f2c8"; + --fa--fa: "\f2c8\f2c8"; } + +.fa-thermometer-three-quarters { + --fa: "\f2c8"; + --fa--fa: "\f2c8\f2c8"; } + +.fa-mobile-screen { + --fa: "\f3cf"; + --fa--fa: "\f3cf\f3cf"; } + +.fa-mobile-android-alt { + --fa: "\f3cf"; + --fa--fa: "\f3cf\f3cf"; } + +.fa-plane-up { + --fa: "\e22d"; + --fa--fa: "\e22d\e22d"; } + +.fa-piggy-bank { + --fa: "\f4d3"; + --fa--fa: "\f4d3\f4d3"; } + +.fa-battery-half { + --fa: "\f242"; + --fa--fa: "\f242\f242"; } + +.fa-battery-3 { + --fa: "\f242"; + --fa--fa: "\f242\f242"; } + +.fa-mountain-city { + --fa: "\e52e"; + --fa--fa: "\e52e\e52e"; } + +.fa-coins { + --fa: "\f51e"; + --fa--fa: "\f51e\f51e"; } + +.fa-khanda { + --fa: "\f66d"; + --fa--fa: "\f66d\f66d"; } + +.fa-sliders { + --fa: "\f1de"; + --fa--fa: "\f1de\f1de"; } + +.fa-sliders-h { + --fa: "\f1de"; + --fa--fa: "\f1de\f1de"; } + +.fa-folder-tree { + --fa: "\f802"; + --fa--fa: "\f802\f802"; } + +.fa-network-wired { + --fa: "\f6ff"; + --fa--fa: "\f6ff\f6ff"; } + +.fa-map-pin { + --fa: "\f276"; + --fa--fa: "\f276\f276"; } + +.fa-hamsa { + --fa: "\f665"; + --fa--fa: "\f665\f665"; } + +.fa-cent-sign { + --fa: "\e3f5"; + --fa--fa: "\e3f5\e3f5"; } + +.fa-flask { + --fa: "\f0c3"; + --fa--fa: "\f0c3\f0c3"; } + +.fa-person-pregnant { + --fa: "\e31e"; + --fa--fa: "\e31e\e31e"; } + +.fa-wand-sparkles { + --fa: "\f72b"; + --fa--fa: "\f72b\f72b"; } + +.fa-ellipsis-vertical { + --fa: "\f142"; + --fa--fa: "\f142\f142"; } + +.fa-ellipsis-v { + --fa: "\f142"; + --fa--fa: "\f142\f142"; } + +.fa-ticket { + --fa: "\f145"; + --fa--fa: "\f145\f145"; } + +.fa-power-off { + --fa: "\f011"; + --fa--fa: "\f011\f011"; } + +.fa-right-long { + --fa: "\f30b"; + --fa--fa: "\f30b\f30b"; } + +.fa-long-arrow-alt-right { + --fa: "\f30b"; + --fa--fa: "\f30b\f30b"; } + +.fa-flag-usa { + --fa: "\f74d"; + --fa--fa: "\f74d\f74d"; } + +.fa-laptop-file { + --fa: "\e51d"; + --fa--fa: "\e51d\e51d"; } + +.fa-tty { + --fa: "\f1e4"; + --fa--fa: "\f1e4\f1e4"; } + +.fa-teletype { + --fa: "\f1e4"; + --fa--fa: "\f1e4\f1e4"; } + +.fa-diagram-next { + --fa: "\e476"; + --fa--fa: "\e476\e476"; } + +.fa-person-rifle { + --fa: "\e54e"; + --fa--fa: "\e54e\e54e"; } + +.fa-house-medical-circle-exclamation { + --fa: "\e512"; + --fa--fa: "\e512\e512"; } + +.fa-closed-captioning { + --fa: "\f20a"; + --fa--fa: "\f20a\f20a"; } + +.fa-person-hiking { + --fa: "\f6ec"; + --fa--fa: "\f6ec\f6ec"; } + +.fa-hiking { + --fa: "\f6ec"; + --fa--fa: "\f6ec\f6ec"; } + +.fa-venus-double { + --fa: "\f226"; + --fa--fa: "\f226\f226"; } + +.fa-images { + --fa: "\f302"; + --fa--fa: "\f302\f302"; } + +.fa-calculator { + --fa: "\f1ec"; + --fa--fa: "\f1ec\f1ec"; } + +.fa-people-pulling { + --fa: "\e535"; + --fa--fa: "\e535\e535"; } + +.fa-n { + --fa: "\4e"; + --fa--fa: "\4e\4e"; } + +.fa-cable-car { + --fa: "\f7da"; + --fa--fa: "\f7da\f7da"; } + +.fa-tram { + --fa: "\f7da"; + --fa--fa: "\f7da\f7da"; } + +.fa-cloud-rain { + --fa: "\f73d"; + --fa--fa: "\f73d\f73d"; } + +.fa-building-circle-xmark { + --fa: "\e4d4"; + --fa--fa: "\e4d4\e4d4"; } + +.fa-ship { + --fa: "\f21a"; + --fa--fa: "\f21a\f21a"; } + +.fa-arrows-down-to-line { + --fa: "\e4b8"; + --fa--fa: "\e4b8\e4b8"; } + +.fa-download { + --fa: "\f019"; + --fa--fa: "\f019\f019"; } + +.fa-face-grin { + --fa: "\f580"; + --fa--fa: "\f580\f580"; } + +.fa-grin { + --fa: "\f580"; + --fa--fa: "\f580\f580"; } + +.fa-delete-left { + --fa: "\f55a"; + --fa--fa: "\f55a\f55a"; } + +.fa-backspace { + --fa: "\f55a"; + --fa--fa: "\f55a\f55a"; } + +.fa-eye-dropper { + --fa: "\f1fb"; + --fa--fa: "\f1fb\f1fb"; } + +.fa-eye-dropper-empty { + --fa: "\f1fb"; + --fa--fa: "\f1fb\f1fb"; } + +.fa-eyedropper { + --fa: "\f1fb"; + --fa--fa: "\f1fb\f1fb"; } + +.fa-file-circle-check { + --fa: "\e5a0"; + --fa--fa: "\e5a0\e5a0"; } + +.fa-forward { + --fa: "\f04e"; + --fa--fa: "\f04e\f04e"; } + +.fa-mobile { + --fa: "\f3ce"; + --fa--fa: "\f3ce\f3ce"; } + +.fa-mobile-android { + --fa: "\f3ce"; + --fa--fa: "\f3ce\f3ce"; } + +.fa-mobile-phone { + --fa: "\f3ce"; + --fa--fa: "\f3ce\f3ce"; } + +.fa-face-meh { + --fa: "\f11a"; + --fa--fa: "\f11a\f11a"; } + +.fa-meh { + --fa: "\f11a"; + --fa--fa: "\f11a\f11a"; } + +.fa-align-center { + --fa: "\f037"; + --fa--fa: "\f037\f037"; } + +.fa-book-skull { + --fa: "\f6b7"; + --fa--fa: "\f6b7\f6b7"; } + +.fa-book-dead { + --fa: "\f6b7"; + --fa--fa: "\f6b7\f6b7"; } + +.fa-id-card { + --fa: "\f2c2"; + --fa--fa: "\f2c2\f2c2"; } + +.fa-drivers-license { + --fa: "\f2c2"; + --fa--fa: "\f2c2\f2c2"; } + +.fa-outdent { + --fa: "\f03b"; + --fa--fa: "\f03b\f03b"; } + +.fa-dedent { + --fa: "\f03b"; + --fa--fa: "\f03b\f03b"; } + +.fa-heart-circle-exclamation { + --fa: "\e4fe"; + --fa--fa: "\e4fe\e4fe"; } + +.fa-house { + --fa: "\f015"; + --fa--fa: "\f015\f015"; } + +.fa-home { + --fa: "\f015"; + --fa--fa: "\f015\f015"; } + +.fa-home-alt { + --fa: "\f015"; + --fa--fa: "\f015\f015"; } + +.fa-home-lg-alt { + --fa: "\f015"; + --fa--fa: "\f015\f015"; } + +.fa-calendar-week { + --fa: "\f784"; + --fa--fa: "\f784\f784"; } + +.fa-laptop-medical { + --fa: "\f812"; + --fa--fa: "\f812\f812"; } + +.fa-b { + --fa: "\42"; + --fa--fa: "\42\42"; } + +.fa-file-medical { + --fa: "\f477"; + --fa--fa: "\f477\f477"; } + +.fa-dice-one { + --fa: "\f525"; + --fa--fa: "\f525\f525"; } + +.fa-kiwi-bird { + --fa: "\f535"; + --fa--fa: "\f535\f535"; } + +.fa-arrow-right-arrow-left { + --fa: "\f0ec"; + --fa--fa: "\f0ec\f0ec"; } + +.fa-exchange { + --fa: "\f0ec"; + --fa--fa: "\f0ec\f0ec"; } + +.fa-rotate-right { + --fa: "\f2f9"; + --fa--fa: "\f2f9\f2f9"; } + +.fa-redo-alt { + --fa: "\f2f9"; + --fa--fa: "\f2f9\f2f9"; } + +.fa-rotate-forward { + --fa: "\f2f9"; + --fa--fa: "\f2f9\f2f9"; } + +.fa-utensils { + --fa: "\f2e7"; + --fa--fa: "\f2e7\f2e7"; } + +.fa-cutlery { + --fa: "\f2e7"; + --fa--fa: "\f2e7\f2e7"; } + +.fa-arrow-up-wide-short { + --fa: "\f161"; + --fa--fa: "\f161\f161"; } + +.fa-sort-amount-up { + --fa: "\f161"; + --fa--fa: "\f161\f161"; } + +.fa-mill-sign { + --fa: "\e1ed"; + --fa--fa: "\e1ed\e1ed"; } + +.fa-bowl-rice { + --fa: "\e2eb"; + --fa--fa: "\e2eb\e2eb"; } + +.fa-skull { + --fa: "\f54c"; + --fa--fa: "\f54c\f54c"; } + +.fa-tower-broadcast { + --fa: "\f519"; + --fa--fa: "\f519\f519"; } + +.fa-broadcast-tower { + --fa: "\f519"; + --fa--fa: "\f519\f519"; } + +.fa-truck-pickup { + --fa: "\f63c"; + --fa--fa: "\f63c\f63c"; } + +.fa-up-long { + --fa: "\f30c"; + --fa--fa: "\f30c\f30c"; } + +.fa-long-arrow-alt-up { + --fa: "\f30c"; + --fa--fa: "\f30c\f30c"; } + +.fa-stop { + --fa: "\f04d"; + --fa--fa: "\f04d\f04d"; } + +.fa-code-merge { + --fa: "\f387"; + --fa--fa: "\f387\f387"; } + +.fa-upload { + --fa: "\f093"; + --fa--fa: "\f093\f093"; } + +.fa-hurricane { + --fa: "\f751"; + --fa--fa: "\f751\f751"; } + +.fa-mound { + --fa: "\e52d"; + --fa--fa: "\e52d\e52d"; } + +.fa-toilet-portable { + --fa: "\e583"; + --fa--fa: "\e583\e583"; } + +.fa-compact-disc { + --fa: "\f51f"; + --fa--fa: "\f51f\f51f"; } + +.fa-file-arrow-down { + --fa: "\f56d"; + --fa--fa: "\f56d\f56d"; } + +.fa-file-download { + --fa: "\f56d"; + --fa--fa: "\f56d\f56d"; } + +.fa-caravan { + --fa: "\f8ff"; + --fa--fa: "\f8ff\f8ff"; } + +.fa-shield-cat { + --fa: "\e572"; + --fa--fa: "\e572\e572"; } + +.fa-bolt { + --fa: "\f0e7"; + --fa--fa: "\f0e7\f0e7"; } + +.fa-zap { + --fa: "\f0e7"; + --fa--fa: "\f0e7\f0e7"; } + +.fa-glass-water { + --fa: "\e4f4"; + --fa--fa: "\e4f4\e4f4"; } + +.fa-oil-well { + --fa: "\e532"; + --fa--fa: "\e532\e532"; } + +.fa-vault { + --fa: "\e2c5"; + --fa--fa: "\e2c5\e2c5"; } + +.fa-mars { + --fa: "\f222"; + --fa--fa: "\f222\f222"; } + +.fa-toilet { + --fa: "\f7d8"; + --fa--fa: "\f7d8\f7d8"; } + +.fa-plane-circle-xmark { + --fa: "\e557"; + --fa--fa: "\e557\e557"; } + +.fa-yen-sign { + --fa: "\f157"; + --fa--fa: "\f157\f157"; } + +.fa-cny { + --fa: "\f157"; + --fa--fa: "\f157\f157"; } + +.fa-jpy { + --fa: "\f157"; + --fa--fa: "\f157\f157"; } + +.fa-rmb { + --fa: "\f157"; + --fa--fa: "\f157\f157"; } + +.fa-yen { + --fa: "\f157"; + --fa--fa: "\f157\f157"; } + +.fa-ruble-sign { + --fa: "\f158"; + --fa--fa: "\f158\f158"; } + +.fa-rouble { + --fa: "\f158"; + --fa--fa: "\f158\f158"; } + +.fa-rub { + --fa: "\f158"; + --fa--fa: "\f158\f158"; } + +.fa-ruble { + --fa: "\f158"; + --fa--fa: "\f158\f158"; } + +.fa-sun { + --fa: "\f185"; + --fa--fa: "\f185\f185"; } + +.fa-guitar { + --fa: "\f7a6"; + --fa--fa: "\f7a6\f7a6"; } + +.fa-face-laugh-wink { + --fa: "\f59c"; + --fa--fa: "\f59c\f59c"; } + +.fa-laugh-wink { + --fa: "\f59c"; + --fa--fa: "\f59c\f59c"; } + +.fa-horse-head { + --fa: "\f7ab"; + --fa--fa: "\f7ab\f7ab"; } + +.fa-bore-hole { + --fa: "\e4c3"; + --fa--fa: "\e4c3\e4c3"; } + +.fa-industry { + --fa: "\f275"; + --fa--fa: "\f275\f275"; } + +.fa-circle-down { + --fa: "\f358"; + --fa--fa: "\f358\f358"; } + +.fa-arrow-alt-circle-down { + --fa: "\f358"; + --fa--fa: "\f358\f358"; } + +.fa-arrows-turn-to-dots { + --fa: "\e4c1"; + --fa--fa: "\e4c1\e4c1"; } + +.fa-florin-sign { + --fa: "\e184"; + --fa--fa: "\e184\e184"; } + +.fa-arrow-down-short-wide { + --fa: "\f884"; + --fa--fa: "\f884\f884"; } + +.fa-sort-amount-desc { + --fa: "\f884"; + --fa--fa: "\f884\f884"; } + +.fa-sort-amount-down-alt { + --fa: "\f884"; + --fa--fa: "\f884\f884"; } + +.fa-less-than { + --fa: "\3c"; + --fa--fa: "\3c\3c"; } + +.fa-angle-down { + --fa: "\f107"; + --fa--fa: "\f107\f107"; } + +.fa-car-tunnel { + --fa: "\e4de"; + --fa--fa: "\e4de\e4de"; } + +.fa-head-side-cough { + --fa: "\e061"; + --fa--fa: "\e061\e061"; } + +.fa-grip-lines { + --fa: "\f7a4"; + --fa--fa: "\f7a4\f7a4"; } + +.fa-thumbs-down { + --fa: "\f165"; + --fa--fa: "\f165\f165"; } + +.fa-user-lock { + --fa: "\f502"; + --fa--fa: "\f502\f502"; } + +.fa-arrow-right-long { + --fa: "\f178"; + --fa--fa: "\f178\f178"; } + +.fa-long-arrow-right { + --fa: "\f178"; + --fa--fa: "\f178\f178"; } + +.fa-anchor-circle-xmark { + --fa: "\e4ac"; + --fa--fa: "\e4ac\e4ac"; } + +.fa-ellipsis { + --fa: "\f141"; + --fa--fa: "\f141\f141"; } + +.fa-ellipsis-h { + --fa: "\f141"; + --fa--fa: "\f141\f141"; } + +.fa-chess-pawn { + --fa: "\f443"; + --fa--fa: "\f443\f443"; } + +.fa-kit-medical { + --fa: "\f479"; + --fa--fa: "\f479\f479"; } + +.fa-first-aid { + --fa: "\f479"; + --fa--fa: "\f479\f479"; } + +.fa-person-through-window { + --fa: "\e5a9"; + --fa--fa: "\e5a9\e5a9"; } + +.fa-toolbox { + --fa: "\f552"; + --fa--fa: "\f552\f552"; } + +.fa-hands-holding-circle { + --fa: "\e4fb"; + --fa--fa: "\e4fb\e4fb"; } + +.fa-bug { + --fa: "\f188"; + --fa--fa: "\f188\f188"; } + +.fa-credit-card { + --fa: "\f09d"; + --fa--fa: "\f09d\f09d"; } + +.fa-credit-card-alt { + --fa: "\f09d"; + --fa--fa: "\f09d\f09d"; } + +.fa-car { + --fa: "\f1b9"; + --fa--fa: "\f1b9\f1b9"; } + +.fa-automobile { + --fa: "\f1b9"; + --fa--fa: "\f1b9\f1b9"; } + +.fa-hand-holding-hand { + --fa: "\e4f7"; + --fa--fa: "\e4f7\e4f7"; } + +.fa-book-open-reader { + --fa: "\f5da"; + --fa--fa: "\f5da\f5da"; } + +.fa-book-reader { + --fa: "\f5da"; + --fa--fa: "\f5da\f5da"; } + +.fa-mountain-sun { + --fa: "\e52f"; + --fa--fa: "\e52f\e52f"; } + +.fa-arrows-left-right-to-line { + --fa: "\e4ba"; + --fa--fa: "\e4ba\e4ba"; } + +.fa-dice-d20 { + --fa: "\f6cf"; + --fa--fa: "\f6cf\f6cf"; } + +.fa-truck-droplet { + --fa: "\e58c"; + --fa--fa: "\e58c\e58c"; } + +.fa-file-circle-xmark { + --fa: "\e5a1"; + --fa--fa: "\e5a1\e5a1"; } + +.fa-temperature-arrow-up { + --fa: "\e040"; + --fa--fa: "\e040\e040"; } + +.fa-temperature-up { + --fa: "\e040"; + --fa--fa: "\e040\e040"; } + +.fa-medal { + --fa: "\f5a2"; + --fa--fa: "\f5a2\f5a2"; } + +.fa-bed { + --fa: "\f236"; + --fa--fa: "\f236\f236"; } + +.fa-square-h { + --fa: "\f0fd"; + --fa--fa: "\f0fd\f0fd"; } + +.fa-h-square { + --fa: "\f0fd"; + --fa--fa: "\f0fd\f0fd"; } + +.fa-podcast { + --fa: "\f2ce"; + --fa--fa: "\f2ce\f2ce"; } + +.fa-temperature-full { + --fa: "\f2c7"; + --fa--fa: "\f2c7\f2c7"; } + +.fa-temperature-4 { + --fa: "\f2c7"; + --fa--fa: "\f2c7\f2c7"; } + +.fa-thermometer-4 { + --fa: "\f2c7"; + --fa--fa: "\f2c7\f2c7"; } + +.fa-thermometer-full { + --fa: "\f2c7"; + --fa--fa: "\f2c7\f2c7"; } + +.fa-bell { + --fa: "\f0f3"; + --fa--fa: "\f0f3\f0f3"; } + +.fa-superscript { + --fa: "\f12b"; + --fa--fa: "\f12b\f12b"; } + +.fa-plug-circle-xmark { + --fa: "\e560"; + --fa--fa: "\e560\e560"; } + +.fa-star-of-life { + --fa: "\f621"; + --fa--fa: "\f621\f621"; } + +.fa-phone-slash { + --fa: "\f3dd"; + --fa--fa: "\f3dd\f3dd"; } + +.fa-paint-roller { + --fa: "\f5aa"; + --fa--fa: "\f5aa\f5aa"; } + +.fa-handshake-angle { + --fa: "\f4c4"; + --fa--fa: "\f4c4\f4c4"; } + +.fa-hands-helping { + --fa: "\f4c4"; + --fa--fa: "\f4c4\f4c4"; } + +.fa-location-dot { + --fa: "\f3c5"; + --fa--fa: "\f3c5\f3c5"; } + +.fa-map-marker-alt { + --fa: "\f3c5"; + --fa--fa: "\f3c5\f3c5"; } + +.fa-file { + --fa: "\f15b"; + --fa--fa: "\f15b\f15b"; } + +.fa-greater-than { + --fa: "\3e"; + --fa--fa: "\3e\3e"; } + +.fa-person-swimming { + --fa: "\f5c4"; + --fa--fa: "\f5c4\f5c4"; } + +.fa-swimmer { + --fa: "\f5c4"; + --fa--fa: "\f5c4\f5c4"; } + +.fa-arrow-down { + --fa: "\f063"; + --fa--fa: "\f063\f063"; } + +.fa-droplet { + --fa: "\f043"; + --fa--fa: "\f043\f043"; } + +.fa-tint { + --fa: "\f043"; + --fa--fa: "\f043\f043"; } + +.fa-eraser { + --fa: "\f12d"; + --fa--fa: "\f12d\f12d"; } + +.fa-earth-americas { + --fa: "\f57d"; + --fa--fa: "\f57d\f57d"; } + +.fa-earth { + --fa: "\f57d"; + --fa--fa: "\f57d\f57d"; } + +.fa-earth-america { + --fa: "\f57d"; + --fa--fa: "\f57d\f57d"; } + +.fa-globe-americas { + --fa: "\f57d"; + --fa--fa: "\f57d\f57d"; } + +.fa-person-burst { + --fa: "\e53b"; + --fa--fa: "\e53b\e53b"; } + +.fa-dove { + --fa: "\f4ba"; + --fa--fa: "\f4ba\f4ba"; } + +.fa-battery-empty { + --fa: "\f244"; + --fa--fa: "\f244\f244"; } + +.fa-battery-0 { + --fa: "\f244"; + --fa--fa: "\f244\f244"; } + +.fa-socks { + --fa: "\f696"; + --fa--fa: "\f696\f696"; } + +.fa-inbox { + --fa: "\f01c"; + --fa--fa: "\f01c\f01c"; } + +.fa-section { + --fa: "\e447"; + --fa--fa: "\e447\e447"; } + +.fa-gauge-high { + --fa: "\f625"; + --fa--fa: "\f625\f625"; } + +.fa-tachometer-alt { + --fa: "\f625"; + --fa--fa: "\f625\f625"; } + +.fa-tachometer-alt-fast { + --fa: "\f625"; + --fa--fa: "\f625\f625"; } + +.fa-envelope-open-text { + --fa: "\f658"; + --fa--fa: "\f658\f658"; } + +.fa-hospital { + --fa: "\f0f8"; + --fa--fa: "\f0f8\f0f8"; } + +.fa-hospital-alt { + --fa: "\f0f8"; + --fa--fa: "\f0f8\f0f8"; } + +.fa-hospital-wide { + --fa: "\f0f8"; + --fa--fa: "\f0f8\f0f8"; } + +.fa-wine-bottle { + --fa: "\f72f"; + --fa--fa: "\f72f\f72f"; } + +.fa-chess-rook { + --fa: "\f447"; + --fa--fa: "\f447\f447"; } + +.fa-bars-staggered { + --fa: "\f550"; + --fa--fa: "\f550\f550"; } + +.fa-reorder { + --fa: "\f550"; + --fa--fa: "\f550\f550"; } + +.fa-stream { + --fa: "\f550"; + --fa--fa: "\f550\f550"; } + +.fa-dharmachakra { + --fa: "\f655"; + --fa--fa: "\f655\f655"; } + +.fa-hotdog { + --fa: "\f80f"; + --fa--fa: "\f80f\f80f"; } + +.fa-person-walking-with-cane { + --fa: "\f29d"; + --fa--fa: "\f29d\f29d"; } + +.fa-blind { + --fa: "\f29d"; + --fa--fa: "\f29d\f29d"; } + +.fa-drum { + --fa: "\f569"; + --fa--fa: "\f569\f569"; } + +.fa-ice-cream { + --fa: "\f810"; + --fa--fa: "\f810\f810"; } + +.fa-heart-circle-bolt { + --fa: "\e4fc"; + --fa--fa: "\e4fc\e4fc"; } + +.fa-fax { + --fa: "\f1ac"; + --fa--fa: "\f1ac\f1ac"; } + +.fa-paragraph { + --fa: "\f1dd"; + --fa--fa: "\f1dd\f1dd"; } + +.fa-check-to-slot { + --fa: "\f772"; + --fa--fa: "\f772\f772"; } + +.fa-vote-yea { + --fa: "\f772"; + --fa--fa: "\f772\f772"; } + +.fa-star-half { + --fa: "\f089"; + --fa--fa: "\f089\f089"; } + +.fa-boxes-stacked { + --fa: "\f468"; + --fa--fa: "\f468\f468"; } + +.fa-boxes { + --fa: "\f468"; + --fa--fa: "\f468\f468"; } + +.fa-boxes-alt { + --fa: "\f468"; + --fa--fa: "\f468\f468"; } + +.fa-link { + --fa: "\f0c1"; + --fa--fa: "\f0c1\f0c1"; } + +.fa-chain { + --fa: "\f0c1"; + --fa--fa: "\f0c1\f0c1"; } + +.fa-ear-listen { + --fa: "\f2a2"; + --fa--fa: "\f2a2\f2a2"; } + +.fa-assistive-listening-systems { + --fa: "\f2a2"; + --fa--fa: "\f2a2\f2a2"; } + +.fa-tree-city { + --fa: "\e587"; + --fa--fa: "\e587\e587"; } + +.fa-play { + --fa: "\f04b"; + --fa--fa: "\f04b\f04b"; } + +.fa-font { + --fa: "\f031"; + --fa--fa: "\f031\f031"; } + +.fa-table-cells-row-lock { + --fa: "\e67a"; + --fa--fa: "\e67a\e67a"; } + +.fa-rupiah-sign { + --fa: "\e23d"; + --fa--fa: "\e23d\e23d"; } + +.fa-magnifying-glass { + --fa: "\f002"; + --fa--fa: "\f002\f002"; } + +.fa-search { + --fa: "\f002"; + --fa--fa: "\f002\f002"; } + +.fa-table-tennis-paddle-ball { + --fa: "\f45d"; + --fa--fa: "\f45d\f45d"; } + +.fa-ping-pong-paddle-ball { + --fa: "\f45d"; + --fa--fa: "\f45d\f45d"; } + +.fa-table-tennis { + --fa: "\f45d"; + --fa--fa: "\f45d\f45d"; } + +.fa-person-dots-from-line { + --fa: "\f470"; + --fa--fa: "\f470\f470"; } + +.fa-diagnoses { + --fa: "\f470"; + --fa--fa: "\f470\f470"; } + +.fa-trash-can-arrow-up { + --fa: "\f82a"; + --fa--fa: "\f82a\f82a"; } + +.fa-trash-restore-alt { + --fa: "\f82a"; + --fa--fa: "\f82a\f82a"; } + +.fa-naira-sign { + --fa: "\e1f6"; + --fa--fa: "\e1f6\e1f6"; } + +.fa-cart-arrow-down { + --fa: "\f218"; + --fa--fa: "\f218\f218"; } + +.fa-walkie-talkie { + --fa: "\f8ef"; + --fa--fa: "\f8ef\f8ef"; } + +.fa-file-pen { + --fa: "\f31c"; + --fa--fa: "\f31c\f31c"; } + +.fa-file-edit { + --fa: "\f31c"; + --fa--fa: "\f31c\f31c"; } + +.fa-receipt { + --fa: "\f543"; + --fa--fa: "\f543\f543"; } + +.fa-square-pen { + --fa: "\f14b"; + --fa--fa: "\f14b\f14b"; } + +.fa-pen-square { + --fa: "\f14b"; + --fa--fa: "\f14b\f14b"; } + +.fa-pencil-square { + --fa: "\f14b"; + --fa--fa: "\f14b\f14b"; } + +.fa-suitcase-rolling { + --fa: "\f5c1"; + --fa--fa: "\f5c1\f5c1"; } + +.fa-person-circle-exclamation { + --fa: "\e53f"; + --fa--fa: "\e53f\e53f"; } + +.fa-chevron-down { + --fa: "\f078"; + --fa--fa: "\f078\f078"; } + +.fa-battery-full { + --fa: "\f240"; + --fa--fa: "\f240\f240"; } + +.fa-battery { + --fa: "\f240"; + --fa--fa: "\f240\f240"; } + +.fa-battery-5 { + --fa: "\f240"; + --fa--fa: "\f240\f240"; } + +.fa-skull-crossbones { + --fa: "\f714"; + --fa--fa: "\f714\f714"; } + +.fa-code-compare { + --fa: "\e13a"; + --fa--fa: "\e13a\e13a"; } + +.fa-list-ul { + --fa: "\f0ca"; + --fa--fa: "\f0ca\f0ca"; } + +.fa-list-dots { + --fa: "\f0ca"; + --fa--fa: "\f0ca\f0ca"; } + +.fa-school-lock { + --fa: "\e56f"; + --fa--fa: "\e56f\e56f"; } + +.fa-tower-cell { + --fa: "\e585"; + --fa--fa: "\e585\e585"; } + +.fa-down-long { + --fa: "\f309"; + --fa--fa: "\f309\f309"; } + +.fa-long-arrow-alt-down { + --fa: "\f309"; + --fa--fa: "\f309\f309"; } + +.fa-ranking-star { + --fa: "\e561"; + --fa--fa: "\e561\e561"; } + +.fa-chess-king { + --fa: "\f43f"; + --fa--fa: "\f43f\f43f"; } + +.fa-person-harassing { + --fa: "\e549"; + --fa--fa: "\e549\e549"; } + +.fa-brazilian-real-sign { + --fa: "\e46c"; + --fa--fa: "\e46c\e46c"; } + +.fa-landmark-dome { + --fa: "\f752"; + --fa--fa: "\f752\f752"; } + +.fa-landmark-alt { + --fa: "\f752"; + --fa--fa: "\f752\f752"; } + +.fa-arrow-up { + --fa: "\f062"; + --fa--fa: "\f062\f062"; } + +.fa-tv { + --fa: "\f26c"; + --fa--fa: "\f26c\f26c"; } + +.fa-television { + --fa: "\f26c"; + --fa--fa: "\f26c\f26c"; } + +.fa-tv-alt { + --fa: "\f26c"; + --fa--fa: "\f26c\f26c"; } + +.fa-shrimp { + --fa: "\e448"; + --fa--fa: "\e448\e448"; } + +.fa-list-check { + --fa: "\f0ae"; + --fa--fa: "\f0ae\f0ae"; } + +.fa-tasks { + --fa: "\f0ae"; + --fa--fa: "\f0ae\f0ae"; } + +.fa-jug-detergent { + --fa: "\e519"; + --fa--fa: "\e519\e519"; } + +.fa-circle-user { + --fa: "\f2bd"; + --fa--fa: "\f2bd\f2bd"; } + +.fa-user-circle { + --fa: "\f2bd"; + --fa--fa: "\f2bd\f2bd"; } + +.fa-user-shield { + --fa: "\f505"; + --fa--fa: "\f505\f505"; } + +.fa-wind { + --fa: "\f72e"; + --fa--fa: "\f72e\f72e"; } + +.fa-car-burst { + --fa: "\f5e1"; + --fa--fa: "\f5e1\f5e1"; } + +.fa-car-crash { + --fa: "\f5e1"; + --fa--fa: "\f5e1\f5e1"; } + +.fa-y { + --fa: "\59"; + --fa--fa: "\59\59"; } + +.fa-person-snowboarding { + --fa: "\f7ce"; + --fa--fa: "\f7ce\f7ce"; } + +.fa-snowboarding { + --fa: "\f7ce"; + --fa--fa: "\f7ce\f7ce"; } + +.fa-truck-fast { + --fa: "\f48b"; + --fa--fa: "\f48b\f48b"; } + +.fa-shipping-fast { + --fa: "\f48b"; + --fa--fa: "\f48b\f48b"; } + +.fa-fish { + --fa: "\f578"; + --fa--fa: "\f578\f578"; } + +.fa-user-graduate { + --fa: "\f501"; + --fa--fa: "\f501\f501"; } + +.fa-circle-half-stroke { + --fa: "\f042"; + --fa--fa: "\f042\f042"; } + +.fa-adjust { + --fa: "\f042"; + --fa--fa: "\f042\f042"; } + +.fa-clapperboard { + --fa: "\e131"; + --fa--fa: "\e131\e131"; } + +.fa-circle-radiation { + --fa: "\f7ba"; + --fa--fa: "\f7ba\f7ba"; } + +.fa-radiation-alt { + --fa: "\f7ba"; + --fa--fa: "\f7ba\f7ba"; } + +.fa-baseball { + --fa: "\f433"; + --fa--fa: "\f433\f433"; } + +.fa-baseball-ball { + --fa: "\f433"; + --fa--fa: "\f433\f433"; } + +.fa-jet-fighter-up { + --fa: "\e518"; + --fa--fa: "\e518\e518"; } + +.fa-diagram-project { + --fa: "\f542"; + --fa--fa: "\f542\f542"; } + +.fa-project-diagram { + --fa: "\f542"; + --fa--fa: "\f542\f542"; } + +.fa-copy { + --fa: "\f0c5"; + --fa--fa: "\f0c5\f0c5"; } + +.fa-volume-xmark { + --fa: "\f6a9"; + --fa--fa: "\f6a9\f6a9"; } + +.fa-volume-mute { + --fa: "\f6a9"; + --fa--fa: "\f6a9\f6a9"; } + +.fa-volume-times { + --fa: "\f6a9"; + --fa--fa: "\f6a9\f6a9"; } + +.fa-hand-sparkles { + --fa: "\e05d"; + --fa--fa: "\e05d\e05d"; } + +.fa-grip { + --fa: "\f58d"; + --fa--fa: "\f58d\f58d"; } + +.fa-grip-horizontal { + --fa: "\f58d"; + --fa--fa: "\f58d\f58d"; } + +.fa-share-from-square { + --fa: "\f14d"; + --fa--fa: "\f14d\f14d"; } + +.fa-share-square { + --fa: "\f14d"; + --fa--fa: "\f14d\f14d"; } + +.fa-child-combatant { + --fa: "\e4e0"; + --fa--fa: "\e4e0\e4e0"; } + +.fa-child-rifle { + --fa: "\e4e0"; + --fa--fa: "\e4e0\e4e0"; } + +.fa-gun { + --fa: "\e19b"; + --fa--fa: "\e19b\e19b"; } + +.fa-square-phone { + --fa: "\f098"; + --fa--fa: "\f098\f098"; } + +.fa-phone-square { + --fa: "\f098"; + --fa--fa: "\f098\f098"; } + +.fa-plus { + --fa: "\2b"; + --fa--fa: "\2b\2b"; } + +.fa-add { + --fa: "\2b"; + --fa--fa: "\2b\2b"; } + +.fa-expand { + --fa: "\f065"; + --fa--fa: "\f065\f065"; } + +.fa-computer { + --fa: "\e4e5"; + --fa--fa: "\e4e5\e4e5"; } + +.fa-xmark { + --fa: "\f00d"; + --fa--fa: "\f00d\f00d"; } + +.fa-close { + --fa: "\f00d"; + --fa--fa: "\f00d\f00d"; } + +.fa-multiply { + --fa: "\f00d"; + --fa--fa: "\f00d\f00d"; } + +.fa-remove { + --fa: "\f00d"; + --fa--fa: "\f00d\f00d"; } + +.fa-times { + --fa: "\f00d"; + --fa--fa: "\f00d\f00d"; } + +.fa-arrows-up-down-left-right { + --fa: "\f047"; + --fa--fa: "\f047\f047"; } + +.fa-arrows { + --fa: "\f047"; + --fa--fa: "\f047\f047"; } + +.fa-chalkboard-user { + --fa: "\f51c"; + --fa--fa: "\f51c\f51c"; } + +.fa-chalkboard-teacher { + --fa: "\f51c"; + --fa--fa: "\f51c\f51c"; } + +.fa-peso-sign { + --fa: "\e222"; + --fa--fa: "\e222\e222"; } + +.fa-building-shield { + --fa: "\e4d8"; + --fa--fa: "\e4d8\e4d8"; } + +.fa-baby { + --fa: "\f77c"; + --fa--fa: "\f77c\f77c"; } + +.fa-users-line { + --fa: "\e592"; + --fa--fa: "\e592\e592"; } + +.fa-quote-left { + --fa: "\f10d"; + --fa--fa: "\f10d\f10d"; } + +.fa-quote-left-alt { + --fa: "\f10d"; + --fa--fa: "\f10d\f10d"; } + +.fa-tractor { + --fa: "\f722"; + --fa--fa: "\f722\f722"; } + +.fa-trash-arrow-up { + --fa: "\f829"; + --fa--fa: "\f829\f829"; } + +.fa-trash-restore { + --fa: "\f829"; + --fa--fa: "\f829\f829"; } + +.fa-arrow-down-up-lock { + --fa: "\e4b0"; + --fa--fa: "\e4b0\e4b0"; } + +.fa-lines-leaning { + --fa: "\e51e"; + --fa--fa: "\e51e\e51e"; } + +.fa-ruler-combined { + --fa: "\f546"; + --fa--fa: "\f546\f546"; } + +.fa-copyright { + --fa: "\f1f9"; + --fa--fa: "\f1f9\f1f9"; } + +.fa-equals { + --fa: "\3d"; + --fa--fa: "\3d\3d"; } + +.fa-blender { + --fa: "\f517"; + --fa--fa: "\f517\f517"; } + +.fa-teeth { + --fa: "\f62e"; + --fa--fa: "\f62e\f62e"; } + +.fa-shekel-sign { + --fa: "\f20b"; + --fa--fa: "\f20b\f20b"; } + +.fa-ils { + --fa: "\f20b"; + --fa--fa: "\f20b\f20b"; } + +.fa-shekel { + --fa: "\f20b"; + --fa--fa: "\f20b\f20b"; } + +.fa-sheqel { + --fa: "\f20b"; + --fa--fa: "\f20b\f20b"; } + +.fa-sheqel-sign { + --fa: "\f20b"; + --fa--fa: "\f20b\f20b"; } + +.fa-map { + --fa: "\f279"; + --fa--fa: "\f279\f279"; } + +.fa-rocket { + --fa: "\f135"; + --fa--fa: "\f135\f135"; } + +.fa-photo-film { + --fa: "\f87c"; + --fa--fa: "\f87c\f87c"; } + +.fa-photo-video { + --fa: "\f87c"; + --fa--fa: "\f87c\f87c"; } + +.fa-folder-minus { + --fa: "\f65d"; + --fa--fa: "\f65d\f65d"; } + +.fa-hexagon-nodes-bolt { + --fa: "\e69a"; + --fa--fa: "\e69a\e69a"; } + +.fa-store { + --fa: "\f54e"; + --fa--fa: "\f54e\f54e"; } + +.fa-arrow-trend-up { + --fa: "\e098"; + --fa--fa: "\e098\e098"; } + +.fa-plug-circle-minus { + --fa: "\e55e"; + --fa--fa: "\e55e\e55e"; } + +.fa-sign-hanging { + --fa: "\f4d9"; + --fa--fa: "\f4d9\f4d9"; } + +.fa-sign { + --fa: "\f4d9"; + --fa--fa: "\f4d9\f4d9"; } + +.fa-bezier-curve { + --fa: "\f55b"; + --fa--fa: "\f55b\f55b"; } + +.fa-bell-slash { + --fa: "\f1f6"; + --fa--fa: "\f1f6\f1f6"; } + +.fa-tablet { + --fa: "\f3fb"; + --fa--fa: "\f3fb\f3fb"; } + +.fa-tablet-android { + --fa: "\f3fb"; + --fa--fa: "\f3fb\f3fb"; } + +.fa-school-flag { + --fa: "\e56e"; + --fa--fa: "\e56e\e56e"; } + +.fa-fill { + --fa: "\f575"; + --fa--fa: "\f575\f575"; } + +.fa-angle-up { + --fa: "\f106"; + --fa--fa: "\f106\f106"; } + +.fa-drumstick-bite { + --fa: "\f6d7"; + --fa--fa: "\f6d7\f6d7"; } + +.fa-holly-berry { + --fa: "\f7aa"; + --fa--fa: "\f7aa\f7aa"; } + +.fa-chevron-left { + --fa: "\f053"; + --fa--fa: "\f053\f053"; } + +.fa-bacteria { + --fa: "\e059"; + --fa--fa: "\e059\e059"; } + +.fa-hand-lizard { + --fa: "\f258"; + --fa--fa: "\f258\f258"; } + +.fa-notdef { + --fa: "\e1fe"; + --fa--fa: "\e1fe\e1fe"; } + +.fa-disease { + --fa: "\f7fa"; + --fa--fa: "\f7fa\f7fa"; } + +.fa-briefcase-medical { + --fa: "\f469"; + --fa--fa: "\f469\f469"; } + +.fa-genderless { + --fa: "\f22d"; + --fa--fa: "\f22d\f22d"; } + +.fa-chevron-right { + --fa: "\f054"; + --fa--fa: "\f054\f054"; } + +.fa-retweet { + --fa: "\f079"; + --fa--fa: "\f079\f079"; } + +.fa-car-rear { + --fa: "\f5de"; + --fa--fa: "\f5de\f5de"; } + +.fa-car-alt { + --fa: "\f5de"; + --fa--fa: "\f5de\f5de"; } + +.fa-pump-soap { + --fa: "\e06b"; + --fa--fa: "\e06b\e06b"; } + +.fa-video-slash { + --fa: "\f4e2"; + --fa--fa: "\f4e2\f4e2"; } + +.fa-battery-quarter { + --fa: "\f243"; + --fa--fa: "\f243\f243"; } + +.fa-battery-2 { + --fa: "\f243"; + --fa--fa: "\f243\f243"; } + +.fa-radio { + --fa: "\f8d7"; + --fa--fa: "\f8d7\f8d7"; } + +.fa-baby-carriage { + --fa: "\f77d"; + --fa--fa: "\f77d\f77d"; } + +.fa-carriage-baby { + --fa: "\f77d"; + --fa--fa: "\f77d\f77d"; } + +.fa-traffic-light { + --fa: "\f637"; + --fa--fa: "\f637\f637"; } + +.fa-thermometer { + --fa: "\f491"; + --fa--fa: "\f491\f491"; } + +.fa-vr-cardboard { + --fa: "\f729"; + --fa--fa: "\f729\f729"; } + +.fa-hand-middle-finger { + --fa: "\f806"; + --fa--fa: "\f806\f806"; } + +.fa-percent { + --fa: "\25"; + --fa--fa: "\25\25"; } + +.fa-percentage { + --fa: "\25"; + --fa--fa: "\25\25"; } + +.fa-truck-moving { + --fa: "\f4df"; + --fa--fa: "\f4df\f4df"; } + +.fa-glass-water-droplet { + --fa: "\e4f5"; + --fa--fa: "\e4f5\e4f5"; } + +.fa-display { + --fa: "\e163"; + --fa--fa: "\e163\e163"; } + +.fa-face-smile { + --fa: "\f118"; + --fa--fa: "\f118\f118"; } + +.fa-smile { + --fa: "\f118"; + --fa--fa: "\f118\f118"; } + +.fa-thumbtack { + --fa: "\f08d"; + --fa--fa: "\f08d\f08d"; } + +.fa-thumb-tack { + --fa: "\f08d"; + --fa--fa: "\f08d\f08d"; } + +.fa-trophy { + --fa: "\f091"; + --fa--fa: "\f091\f091"; } + +.fa-person-praying { + --fa: "\f683"; + --fa--fa: "\f683\f683"; } + +.fa-pray { + --fa: "\f683"; + --fa--fa: "\f683\f683"; } + +.fa-hammer { + --fa: "\f6e3"; + --fa--fa: "\f6e3\f6e3"; } + +.fa-hand-peace { + --fa: "\f25b"; + --fa--fa: "\f25b\f25b"; } + +.fa-rotate { + --fa: "\f2f1"; + --fa--fa: "\f2f1\f2f1"; } + +.fa-sync-alt { + --fa: "\f2f1"; + --fa--fa: "\f2f1\f2f1"; } + +.fa-spinner { + --fa: "\f110"; + --fa--fa: "\f110\f110"; } + +.fa-robot { + --fa: "\f544"; + --fa--fa: "\f544\f544"; } + +.fa-peace { + --fa: "\f67c"; + --fa--fa: "\f67c\f67c"; } + +.fa-gears { + --fa: "\f085"; + --fa--fa: "\f085\f085"; } + +.fa-cogs { + --fa: "\f085"; + --fa--fa: "\f085\f085"; } + +.fa-warehouse { + --fa: "\f494"; + --fa--fa: "\f494\f494"; } + +.fa-arrow-up-right-dots { + --fa: "\e4b7"; + --fa--fa: "\e4b7\e4b7"; } + +.fa-splotch { + --fa: "\f5bc"; + --fa--fa: "\f5bc\f5bc"; } + +.fa-face-grin-hearts { + --fa: "\f584"; + --fa--fa: "\f584\f584"; } + +.fa-grin-hearts { + --fa: "\f584"; + --fa--fa: "\f584\f584"; } + +.fa-dice-four { + --fa: "\f524"; + --fa--fa: "\f524\f524"; } + +.fa-sim-card { + --fa: "\f7c4"; + --fa--fa: "\f7c4\f7c4"; } + +.fa-transgender { + --fa: "\f225"; + --fa--fa: "\f225\f225"; } + +.fa-transgender-alt { + --fa: "\f225"; + --fa--fa: "\f225\f225"; } + +.fa-mercury { + --fa: "\f223"; + --fa--fa: "\f223\f223"; } + +.fa-arrow-turn-down { + --fa: "\f149"; + --fa--fa: "\f149\f149"; } + +.fa-level-down { + --fa: "\f149"; + --fa--fa: "\f149\f149"; } + +.fa-person-falling-burst { + --fa: "\e547"; + --fa--fa: "\e547\e547"; } + +.fa-award { + --fa: "\f559"; + --fa--fa: "\f559\f559"; } + +.fa-ticket-simple { + --fa: "\f3ff"; + --fa--fa: "\f3ff\f3ff"; } + +.fa-ticket-alt { + --fa: "\f3ff"; + --fa--fa: "\f3ff\f3ff"; } + +.fa-building { + --fa: "\f1ad"; + --fa--fa: "\f1ad\f1ad"; } + +.fa-angles-left { + --fa: "\f100"; + --fa--fa: "\f100\f100"; } + +.fa-angle-double-left { + --fa: "\f100"; + --fa--fa: "\f100\f100"; } + +.fa-qrcode { + --fa: "\f029"; + --fa--fa: "\f029\f029"; } + +.fa-clock-rotate-left { + --fa: "\f1da"; + --fa--fa: "\f1da\f1da"; } + +.fa-history { + --fa: "\f1da"; + --fa--fa: "\f1da\f1da"; } + +.fa-face-grin-beam-sweat { + --fa: "\f583"; + --fa--fa: "\f583\f583"; } + +.fa-grin-beam-sweat { + --fa: "\f583"; + --fa--fa: "\f583\f583"; } + +.fa-file-export { + --fa: "\f56e"; + --fa--fa: "\f56e\f56e"; } + +.fa-arrow-right-from-file { + --fa: "\f56e"; + --fa--fa: "\f56e\f56e"; } + +.fa-shield { + --fa: "\f132"; + --fa--fa: "\f132\f132"; } + +.fa-shield-blank { + --fa: "\f132"; + --fa--fa: "\f132\f132"; } + +.fa-arrow-up-short-wide { + --fa: "\f885"; + --fa--fa: "\f885\f885"; } + +.fa-sort-amount-up-alt { + --fa: "\f885"; + --fa--fa: "\f885\f885"; } + +.fa-comment-nodes { + --fa: "\e696"; + --fa--fa: "\e696\e696"; } + +.fa-house-medical { + --fa: "\e3b2"; + --fa--fa: "\e3b2\e3b2"; } + +.fa-golf-ball-tee { + --fa: "\f450"; + --fa--fa: "\f450\f450"; } + +.fa-golf-ball { + --fa: "\f450"; + --fa--fa: "\f450\f450"; } + +.fa-circle-chevron-left { + --fa: "\f137"; + --fa--fa: "\f137\f137"; } + +.fa-chevron-circle-left { + --fa: "\f137"; + --fa--fa: "\f137\f137"; } + +.fa-house-chimney-window { + --fa: "\e00d"; + --fa--fa: "\e00d\e00d"; } + +.fa-pen-nib { + --fa: "\f5ad"; + --fa--fa: "\f5ad\f5ad"; } + +.fa-tent-arrow-turn-left { + --fa: "\e580"; + --fa--fa: "\e580\e580"; } + +.fa-tents { + --fa: "\e582"; + --fa--fa: "\e582\e582"; } + +.fa-wand-magic { + --fa: "\f0d0"; + --fa--fa: "\f0d0\f0d0"; } + +.fa-magic { + --fa: "\f0d0"; + --fa--fa: "\f0d0\f0d0"; } + +.fa-dog { + --fa: "\f6d3"; + --fa--fa: "\f6d3\f6d3"; } + +.fa-carrot { + --fa: "\f787"; + --fa--fa: "\f787\f787"; } + +.fa-moon { + --fa: "\f186"; + --fa--fa: "\f186\f186"; } + +.fa-wine-glass-empty { + --fa: "\f5ce"; + --fa--fa: "\f5ce\f5ce"; } + +.fa-wine-glass-alt { + --fa: "\f5ce"; + --fa--fa: "\f5ce\f5ce"; } + +.fa-cheese { + --fa: "\f7ef"; + --fa--fa: "\f7ef\f7ef"; } + +.fa-yin-yang { + --fa: "\f6ad"; + --fa--fa: "\f6ad\f6ad"; } + +.fa-music { + --fa: "\f001"; + --fa--fa: "\f001\f001"; } + +.fa-code-commit { + --fa: "\f386"; + --fa--fa: "\f386\f386"; } + +.fa-temperature-low { + --fa: "\f76b"; + --fa--fa: "\f76b\f76b"; } + +.fa-person-biking { + --fa: "\f84a"; + --fa--fa: "\f84a\f84a"; } + +.fa-biking { + --fa: "\f84a"; + --fa--fa: "\f84a\f84a"; } + +.fa-broom { + --fa: "\f51a"; + --fa--fa: "\f51a\f51a"; } + +.fa-shield-heart { + --fa: "\e574"; + --fa--fa: "\e574\e574"; } + +.fa-gopuram { + --fa: "\f664"; + --fa--fa: "\f664\f664"; } + +.fa-earth-oceania { + --fa: "\e47b"; + --fa--fa: "\e47b\e47b"; } + +.fa-globe-oceania { + --fa: "\e47b"; + --fa--fa: "\e47b\e47b"; } + +.fa-square-xmark { + --fa: "\f2d3"; + --fa--fa: "\f2d3\f2d3"; } + +.fa-times-square { + --fa: "\f2d3"; + --fa--fa: "\f2d3\f2d3"; } + +.fa-xmark-square { + --fa: "\f2d3"; + --fa--fa: "\f2d3\f2d3"; } + +.fa-hashtag { + --fa: "\23"; + --fa--fa: "\23\23"; } + +.fa-up-right-and-down-left-from-center { + --fa: "\f424"; + --fa--fa: "\f424\f424"; } + +.fa-expand-alt { + --fa: "\f424"; + --fa--fa: "\f424\f424"; } + +.fa-oil-can { + --fa: "\f613"; + --fa--fa: "\f613\f613"; } + +.fa-t { + --fa: "\54"; + --fa--fa: "\54\54"; } + +.fa-hippo { + --fa: "\f6ed"; + --fa--fa: "\f6ed\f6ed"; } + +.fa-chart-column { + --fa: "\e0e3"; + --fa--fa: "\e0e3\e0e3"; } + +.fa-infinity { + --fa: "\f534"; + --fa--fa: "\f534\f534"; } + +.fa-vial-circle-check { + --fa: "\e596"; + --fa--fa: "\e596\e596"; } + +.fa-person-arrow-down-to-line { + --fa: "\e538"; + --fa--fa: "\e538\e538"; } + +.fa-voicemail { + --fa: "\f897"; + --fa--fa: "\f897\f897"; } + +.fa-fan { + --fa: "\f863"; + --fa--fa: "\f863\f863"; } + +.fa-person-walking-luggage { + --fa: "\e554"; + --fa--fa: "\e554\e554"; } + +.fa-up-down { + --fa: "\f338"; + --fa--fa: "\f338\f338"; } + +.fa-arrows-alt-v { + --fa: "\f338"; + --fa--fa: "\f338\f338"; } + +.fa-cloud-moon-rain { + --fa: "\f73c"; + --fa--fa: "\f73c\f73c"; } + +.fa-calendar { + --fa: "\f133"; + --fa--fa: "\f133\f133"; } + +.fa-trailer { + --fa: "\e041"; + --fa--fa: "\e041\e041"; } + +.fa-bahai { + --fa: "\f666"; + --fa--fa: "\f666\f666"; } + +.fa-haykal { + --fa: "\f666"; + --fa--fa: "\f666\f666"; } + +.fa-sd-card { + --fa: "\f7c2"; + --fa--fa: "\f7c2\f7c2"; } + +.fa-dragon { + --fa: "\f6d5"; + --fa--fa: "\f6d5\f6d5"; } + +.fa-shoe-prints { + --fa: "\f54b"; + --fa--fa: "\f54b\f54b"; } + +.fa-circle-plus { + --fa: "\f055"; + --fa--fa: "\f055\f055"; } + +.fa-plus-circle { + --fa: "\f055"; + --fa--fa: "\f055\f055"; } + +.fa-face-grin-tongue-wink { + --fa: "\f58b"; + --fa--fa: "\f58b\f58b"; } + +.fa-grin-tongue-wink { + --fa: "\f58b"; + --fa--fa: "\f58b\f58b"; } + +.fa-hand-holding { + --fa: "\f4bd"; + --fa--fa: "\f4bd\f4bd"; } + +.fa-plug-circle-exclamation { + --fa: "\e55d"; + --fa--fa: "\e55d\e55d"; } + +.fa-link-slash { + --fa: "\f127"; + --fa--fa: "\f127\f127"; } + +.fa-chain-broken { + --fa: "\f127"; + --fa--fa: "\f127\f127"; } + +.fa-chain-slash { + --fa: "\f127"; + --fa--fa: "\f127\f127"; } + +.fa-unlink { + --fa: "\f127"; + --fa--fa: "\f127\f127"; } + +.fa-clone { + --fa: "\f24d"; + --fa--fa: "\f24d\f24d"; } + +.fa-person-walking-arrow-loop-left { + --fa: "\e551"; + --fa--fa: "\e551\e551"; } + +.fa-arrow-up-z-a { + --fa: "\f882"; + --fa--fa: "\f882\f882"; } + +.fa-sort-alpha-up-alt { + --fa: "\f882"; + --fa--fa: "\f882\f882"; } + +.fa-fire-flame-curved { + --fa: "\f7e4"; + --fa--fa: "\f7e4\f7e4"; } + +.fa-fire-alt { + --fa: "\f7e4"; + --fa--fa: "\f7e4\f7e4"; } + +.fa-tornado { + --fa: "\f76f"; + --fa--fa: "\f76f\f76f"; } + +.fa-file-circle-plus { + --fa: "\e494"; + --fa--fa: "\e494\e494"; } + +.fa-book-quran { + --fa: "\f687"; + --fa--fa: "\f687\f687"; } + +.fa-quran { + --fa: "\f687"; + --fa--fa: "\f687\f687"; } + +.fa-anchor { + --fa: "\f13d"; + --fa--fa: "\f13d\f13d"; } + +.fa-border-all { + --fa: "\f84c"; + --fa--fa: "\f84c\f84c"; } + +.fa-face-angry { + --fa: "\f556"; + --fa--fa: "\f556\f556"; } + +.fa-angry { + --fa: "\f556"; + --fa--fa: "\f556\f556"; } + +.fa-cookie-bite { + --fa: "\f564"; + --fa--fa: "\f564\f564"; } + +.fa-arrow-trend-down { + --fa: "\e097"; + --fa--fa: "\e097\e097"; } + +.fa-rss { + --fa: "\f09e"; + --fa--fa: "\f09e\f09e"; } + +.fa-feed { + --fa: "\f09e"; + --fa--fa: "\f09e\f09e"; } + +.fa-draw-polygon { + --fa: "\f5ee"; + --fa--fa: "\f5ee\f5ee"; } + +.fa-scale-balanced { + --fa: "\f24e"; + --fa--fa: "\f24e\f24e"; } + +.fa-balance-scale { + --fa: "\f24e"; + --fa--fa: "\f24e\f24e"; } + +.fa-gauge-simple-high { + --fa: "\f62a"; + --fa--fa: "\f62a\f62a"; } + +.fa-tachometer { + --fa: "\f62a"; + --fa--fa: "\f62a\f62a"; } + +.fa-tachometer-fast { + --fa: "\f62a"; + --fa--fa: "\f62a\f62a"; } + +.fa-shower { + --fa: "\f2cc"; + --fa--fa: "\f2cc\f2cc"; } + +.fa-desktop { + --fa: "\f390"; + --fa--fa: "\f390\f390"; } + +.fa-desktop-alt { + --fa: "\f390"; + --fa--fa: "\f390\f390"; } + +.fa-m { + --fa: "\4d"; + --fa--fa: "\4d\4d"; } + +.fa-table-list { + --fa: "\f00b"; + --fa--fa: "\f00b\f00b"; } + +.fa-th-list { + --fa: "\f00b"; + --fa--fa: "\f00b\f00b"; } + +.fa-comment-sms { + --fa: "\f7cd"; + --fa--fa: "\f7cd\f7cd"; } + +.fa-sms { + --fa: "\f7cd"; + --fa--fa: "\f7cd\f7cd"; } + +.fa-book { + --fa: "\f02d"; + --fa--fa: "\f02d\f02d"; } + +.fa-user-plus { + --fa: "\f234"; + --fa--fa: "\f234\f234"; } + +.fa-check { + --fa: "\f00c"; + --fa--fa: "\f00c\f00c"; } + +.fa-battery-three-quarters { + --fa: "\f241"; + --fa--fa: "\f241\f241"; } + +.fa-battery-4 { + --fa: "\f241"; + --fa--fa: "\f241\f241"; } + +.fa-house-circle-check { + --fa: "\e509"; + --fa--fa: "\e509\e509"; } + +.fa-angle-left { + --fa: "\f104"; + --fa--fa: "\f104\f104"; } + +.fa-diagram-successor { + --fa: "\e47a"; + --fa--fa: "\e47a\e47a"; } + +.fa-truck-arrow-right { + --fa: "\e58b"; + --fa--fa: "\e58b\e58b"; } + +.fa-arrows-split-up-and-left { + --fa: "\e4bc"; + --fa--fa: "\e4bc\e4bc"; } + +.fa-hand-fist { + --fa: "\f6de"; + --fa--fa: "\f6de\f6de"; } + +.fa-fist-raised { + --fa: "\f6de"; + --fa--fa: "\f6de\f6de"; } + +.fa-cloud-moon { + --fa: "\f6c3"; + --fa--fa: "\f6c3\f6c3"; } + +.fa-briefcase { + --fa: "\f0b1"; + --fa--fa: "\f0b1\f0b1"; } + +.fa-person-falling { + --fa: "\e546"; + --fa--fa: "\e546\e546"; } + +.fa-image-portrait { + --fa: "\f3e0"; + --fa--fa: "\f3e0\f3e0"; } + +.fa-portrait { + --fa: "\f3e0"; + --fa--fa: "\f3e0\f3e0"; } + +.fa-user-tag { + --fa: "\f507"; + --fa--fa: "\f507\f507"; } + +.fa-rug { + --fa: "\e569"; + --fa--fa: "\e569\e569"; } + +.fa-earth-europe { + --fa: "\f7a2"; + --fa--fa: "\f7a2\f7a2"; } + +.fa-globe-europe { + --fa: "\f7a2"; + --fa--fa: "\f7a2\f7a2"; } + +.fa-cart-flatbed-suitcase { + --fa: "\f59d"; + --fa--fa: "\f59d\f59d"; } + +.fa-luggage-cart { + --fa: "\f59d"; + --fa--fa: "\f59d\f59d"; } + +.fa-rectangle-xmark { + --fa: "\f410"; + --fa--fa: "\f410\f410"; } + +.fa-rectangle-times { + --fa: "\f410"; + --fa--fa: "\f410\f410"; } + +.fa-times-rectangle { + --fa: "\f410"; + --fa--fa: "\f410\f410"; } + +.fa-window-close { + --fa: "\f410"; + --fa--fa: "\f410\f410"; } + +.fa-baht-sign { + --fa: "\e0ac"; + --fa--fa: "\e0ac\e0ac"; } + +.fa-book-open { + --fa: "\f518"; + --fa--fa: "\f518\f518"; } + +.fa-book-journal-whills { + --fa: "\f66a"; + --fa--fa: "\f66a\f66a"; } + +.fa-journal-whills { + --fa: "\f66a"; + --fa--fa: "\f66a\f66a"; } + +.fa-handcuffs { + --fa: "\e4f8"; + --fa--fa: "\e4f8\e4f8"; } + +.fa-triangle-exclamation { + --fa: "\f071"; + --fa--fa: "\f071\f071"; } + +.fa-exclamation-triangle { + --fa: "\f071"; + --fa--fa: "\f071\f071"; } + +.fa-warning { + --fa: "\f071"; + --fa--fa: "\f071\f071"; } + +.fa-database { + --fa: "\f1c0"; + --fa--fa: "\f1c0\f1c0"; } + +.fa-share { + --fa: "\f064"; + --fa--fa: "\f064\f064"; } + +.fa-mail-forward { + --fa: "\f064"; + --fa--fa: "\f064\f064"; } + +.fa-bottle-droplet { + --fa: "\e4c4"; + --fa--fa: "\e4c4\e4c4"; } + +.fa-mask-face { + --fa: "\e1d7"; + --fa--fa: "\e1d7\e1d7"; } + +.fa-hill-rockslide { + --fa: "\e508"; + --fa--fa: "\e508\e508"; } + +.fa-right-left { + --fa: "\f362"; + --fa--fa: "\f362\f362"; } + +.fa-exchange-alt { + --fa: "\f362"; + --fa--fa: "\f362\f362"; } + +.fa-paper-plane { + --fa: "\f1d8"; + --fa--fa: "\f1d8\f1d8"; } + +.fa-road-circle-exclamation { + --fa: "\e565"; + --fa--fa: "\e565\e565"; } + +.fa-dungeon { + --fa: "\f6d9"; + --fa--fa: "\f6d9\f6d9"; } + +.fa-align-right { + --fa: "\f038"; + --fa--fa: "\f038\f038"; } + +.fa-money-bill-1-wave { + --fa: "\f53b"; + --fa--fa: "\f53b\f53b"; } + +.fa-money-bill-wave-alt { + --fa: "\f53b"; + --fa--fa: "\f53b\f53b"; } + +.fa-life-ring { + --fa: "\f1cd"; + --fa--fa: "\f1cd\f1cd"; } + +.fa-hands { + --fa: "\f2a7"; + --fa--fa: "\f2a7\f2a7"; } + +.fa-sign-language { + --fa: "\f2a7"; + --fa--fa: "\f2a7\f2a7"; } + +.fa-signing { + --fa: "\f2a7"; + --fa--fa: "\f2a7\f2a7"; } + +.fa-calendar-day { + --fa: "\f783"; + --fa--fa: "\f783\f783"; } + +.fa-water-ladder { + --fa: "\f5c5"; + --fa--fa: "\f5c5\f5c5"; } + +.fa-ladder-water { + --fa: "\f5c5"; + --fa--fa: "\f5c5\f5c5"; } + +.fa-swimming-pool { + --fa: "\f5c5"; + --fa--fa: "\f5c5\f5c5"; } + +.fa-arrows-up-down { + --fa: "\f07d"; + --fa--fa: "\f07d\f07d"; } + +.fa-arrows-v { + --fa: "\f07d"; + --fa--fa: "\f07d\f07d"; } + +.fa-face-grimace { + --fa: "\f57f"; + --fa--fa: "\f57f\f57f"; } + +.fa-grimace { + --fa: "\f57f"; + --fa--fa: "\f57f\f57f"; } + +.fa-wheelchair-move { + --fa: "\e2ce"; + --fa--fa: "\e2ce\e2ce"; } + +.fa-wheelchair-alt { + --fa: "\e2ce"; + --fa--fa: "\e2ce\e2ce"; } + +.fa-turn-down { + --fa: "\f3be"; + --fa--fa: "\f3be\f3be"; } + +.fa-level-down-alt { + --fa: "\f3be"; + --fa--fa: "\f3be\f3be"; } + +.fa-person-walking-arrow-right { + --fa: "\e552"; + --fa--fa: "\e552\e552"; } + +.fa-square-envelope { + --fa: "\f199"; + --fa--fa: "\f199\f199"; } + +.fa-envelope-square { + --fa: "\f199"; + --fa--fa: "\f199\f199"; } + +.fa-dice { + --fa: "\f522"; + --fa--fa: "\f522\f522"; } + +.fa-bowling-ball { + --fa: "\f436"; + --fa--fa: "\f436\f436"; } + +.fa-brain { + --fa: "\f5dc"; + --fa--fa: "\f5dc\f5dc"; } + +.fa-bandage { + --fa: "\f462"; + --fa--fa: "\f462\f462"; } + +.fa-band-aid { + --fa: "\f462"; + --fa--fa: "\f462\f462"; } + +.fa-calendar-minus { + --fa: "\f272"; + --fa--fa: "\f272\f272"; } + +.fa-circle-xmark { + --fa: "\f057"; + --fa--fa: "\f057\f057"; } + +.fa-times-circle { + --fa: "\f057"; + --fa--fa: "\f057\f057"; } + +.fa-xmark-circle { + --fa: "\f057"; + --fa--fa: "\f057\f057"; } + +.fa-gifts { + --fa: "\f79c"; + --fa--fa: "\f79c\f79c"; } + +.fa-hotel { + --fa: "\f594"; + --fa--fa: "\f594\f594"; } + +.fa-earth-asia { + --fa: "\f57e"; + --fa--fa: "\f57e\f57e"; } + +.fa-globe-asia { + --fa: "\f57e"; + --fa--fa: "\f57e\f57e"; } + +.fa-id-card-clip { + --fa: "\f47f"; + --fa--fa: "\f47f\f47f"; } + +.fa-id-card-alt { + --fa: "\f47f"; + --fa--fa: "\f47f\f47f"; } + +.fa-magnifying-glass-plus { + --fa: "\f00e"; + --fa--fa: "\f00e\f00e"; } + +.fa-search-plus { + --fa: "\f00e"; + --fa--fa: "\f00e\f00e"; } + +.fa-thumbs-up { + --fa: "\f164"; + --fa--fa: "\f164\f164"; } + +.fa-user-clock { + --fa: "\f4fd"; + --fa--fa: "\f4fd\f4fd"; } + +.fa-hand-dots { + --fa: "\f461"; + --fa--fa: "\f461\f461"; } + +.fa-allergies { + --fa: "\f461"; + --fa--fa: "\f461\f461"; } + +.fa-file-invoice { + --fa: "\f570"; + --fa--fa: "\f570\f570"; } + +.fa-window-minimize { + --fa: "\f2d1"; + --fa--fa: "\f2d1\f2d1"; } + +.fa-mug-saucer { + --fa: "\f0f4"; + --fa--fa: "\f0f4\f0f4"; } + +.fa-coffee { + --fa: "\f0f4"; + --fa--fa: "\f0f4\f0f4"; } + +.fa-brush { + --fa: "\f55d"; + --fa--fa: "\f55d\f55d"; } + +.fa-file-half-dashed { + --fa: "\e698"; + --fa--fa: "\e698\e698"; } + +.fa-mask { + --fa: "\f6fa"; + --fa--fa: "\f6fa\f6fa"; } + +.fa-magnifying-glass-minus { + --fa: "\f010"; + --fa--fa: "\f010\f010"; } + +.fa-search-minus { + --fa: "\f010"; + --fa--fa: "\f010\f010"; } + +.fa-ruler-vertical { + --fa: "\f548"; + --fa--fa: "\f548\f548"; } + +.fa-user-large { + --fa: "\f406"; + --fa--fa: "\f406\f406"; } + +.fa-user-alt { + --fa: "\f406"; + --fa--fa: "\f406\f406"; } + +.fa-train-tram { + --fa: "\e5b4"; + --fa--fa: "\e5b4\e5b4"; } + +.fa-user-nurse { + --fa: "\f82f"; + --fa--fa: "\f82f\f82f"; } + +.fa-syringe { + --fa: "\f48e"; + --fa--fa: "\f48e\f48e"; } + +.fa-cloud-sun { + --fa: "\f6c4"; + --fa--fa: "\f6c4\f6c4"; } + +.fa-stopwatch-20 { + --fa: "\e06f"; + --fa--fa: "\e06f\e06f"; } + +.fa-square-full { + --fa: "\f45c"; + --fa--fa: "\f45c\f45c"; } + +.fa-magnet { + --fa: "\f076"; + --fa--fa: "\f076\f076"; } + +.fa-jar { + --fa: "\e516"; + --fa--fa: "\e516\e516"; } + +.fa-note-sticky { + --fa: "\f249"; + --fa--fa: "\f249\f249"; } + +.fa-sticky-note { + --fa: "\f249"; + --fa--fa: "\f249\f249"; } + +.fa-bug-slash { + --fa: "\e490"; + --fa--fa: "\e490\e490"; } + +.fa-arrow-up-from-water-pump { + --fa: "\e4b6"; + --fa--fa: "\e4b6\e4b6"; } + +.fa-bone { + --fa: "\f5d7"; + --fa--fa: "\f5d7\f5d7"; } + +.fa-table-cells-row-unlock { + --fa: "\e691"; + --fa--fa: "\e691\e691"; } + +.fa-user-injured { + --fa: "\f728"; + --fa--fa: "\f728\f728"; } + +.fa-face-sad-tear { + --fa: "\f5b4"; + --fa--fa: "\f5b4\f5b4"; } + +.fa-sad-tear { + --fa: "\f5b4"; + --fa--fa: "\f5b4\f5b4"; } + +.fa-plane { + --fa: "\f072"; + --fa--fa: "\f072\f072"; } + +.fa-tent-arrows-down { + --fa: "\e581"; + --fa--fa: "\e581\e581"; } + +.fa-exclamation { + --fa: "\21"; + --fa--fa: "\21\21"; } + +.fa-arrows-spin { + --fa: "\e4bb"; + --fa--fa: "\e4bb\e4bb"; } + +.fa-print { + --fa: "\f02f"; + --fa--fa: "\f02f\f02f"; } + +.fa-turkish-lira-sign { + --fa: "\e2bb"; + --fa--fa: "\e2bb\e2bb"; } + +.fa-try { + --fa: "\e2bb"; + --fa--fa: "\e2bb\e2bb"; } + +.fa-turkish-lira { + --fa: "\e2bb"; + --fa--fa: "\e2bb\e2bb"; } + +.fa-dollar-sign { + --fa: "\24"; + --fa--fa: "\24\24"; } + +.fa-dollar { + --fa: "\24"; + --fa--fa: "\24\24"; } + +.fa-usd { + --fa: "\24"; + --fa--fa: "\24\24"; } + +.fa-x { + --fa: "\58"; + --fa--fa: "\58\58"; } + +.fa-magnifying-glass-dollar { + --fa: "\f688"; + --fa--fa: "\f688\f688"; } + +.fa-search-dollar { + --fa: "\f688"; + --fa--fa: "\f688\f688"; } + +.fa-users-gear { + --fa: "\f509"; + --fa--fa: "\f509\f509"; } + +.fa-users-cog { + --fa: "\f509"; + --fa--fa: "\f509\f509"; } + +.fa-person-military-pointing { + --fa: "\e54a"; + --fa--fa: "\e54a\e54a"; } + +.fa-building-columns { + --fa: "\f19c"; + --fa--fa: "\f19c\f19c"; } + +.fa-bank { + --fa: "\f19c"; + --fa--fa: "\f19c\f19c"; } + +.fa-institution { + --fa: "\f19c"; + --fa--fa: "\f19c\f19c"; } + +.fa-museum { + --fa: "\f19c"; + --fa--fa: "\f19c\f19c"; } + +.fa-university { + --fa: "\f19c"; + --fa--fa: "\f19c\f19c"; } + +.fa-umbrella { + --fa: "\f0e9"; + --fa--fa: "\f0e9\f0e9"; } + +.fa-trowel { + --fa: "\e589"; + --fa--fa: "\e589\e589"; } + +.fa-d { + --fa: "\44"; + --fa--fa: "\44\44"; } + +.fa-stapler { + --fa: "\e5af"; + --fa--fa: "\e5af\e5af"; } + +.fa-masks-theater { + --fa: "\f630"; + --fa--fa: "\f630\f630"; } + +.fa-theater-masks { + --fa: "\f630"; + --fa--fa: "\f630\f630"; } + +.fa-kip-sign { + --fa: "\e1c4"; + --fa--fa: "\e1c4\e1c4"; } + +.fa-hand-point-left { + --fa: "\f0a5"; + --fa--fa: "\f0a5\f0a5"; } + +.fa-handshake-simple { + --fa: "\f4c6"; + --fa--fa: "\f4c6\f4c6"; } + +.fa-handshake-alt { + --fa: "\f4c6"; + --fa--fa: "\f4c6\f4c6"; } + +.fa-jet-fighter { + --fa: "\f0fb"; + --fa--fa: "\f0fb\f0fb"; } + +.fa-fighter-jet { + --fa: "\f0fb"; + --fa--fa: "\f0fb\f0fb"; } + +.fa-square-share-nodes { + --fa: "\f1e1"; + --fa--fa: "\f1e1\f1e1"; } + +.fa-share-alt-square { + --fa: "\f1e1"; + --fa--fa: "\f1e1\f1e1"; } + +.fa-barcode { + --fa: "\f02a"; + --fa--fa: "\f02a\f02a"; } + +.fa-plus-minus { + --fa: "\e43c"; + --fa--fa: "\e43c\e43c"; } + +.fa-video { + --fa: "\f03d"; + --fa--fa: "\f03d\f03d"; } + +.fa-video-camera { + --fa: "\f03d"; + --fa--fa: "\f03d\f03d"; } + +.fa-graduation-cap { + --fa: "\f19d"; + --fa--fa: "\f19d\f19d"; } + +.fa-mortar-board { + --fa: "\f19d"; + --fa--fa: "\f19d\f19d"; } + +.fa-hand-holding-medical { + --fa: "\e05c"; + --fa--fa: "\e05c\e05c"; } + +.fa-person-circle-check { + --fa: "\e53e"; + --fa--fa: "\e53e\e53e"; } + +.fa-turn-up { + --fa: "\f3bf"; + --fa--fa: "\f3bf\f3bf"; } + +.fa-level-up-alt { + --fa: "\f3bf"; + --fa--fa: "\f3bf\f3bf"; } + +.sr-only, +.fa-sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; } + +.sr-only-focusable:not(:focus), +.fa-sr-only-focusable:not(:focus) { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; } + +/*! + * Font Awesome Free 6.7.1 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +:root, :host { + --fa-style-family-classic: 'Font Awesome 6 Free'; + --fa-font-regular: normal 400 1em/1 'Font Awesome 6 Free'; } + +@font-face { + font-family: 'Font Awesome 6 Free'; + font-style: normal; + font-weight: 400; + font-display: block; + src: url("../fonts/fa-regular-400.woff2") format("woff2"), url("../fonts/fa-regular-400.ttf") format("truetype"); } + +.far, +.fa-regular { + font-weight: 400; } + +/*! + * Font Awesome Free 6.7.1 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +:root, :host { + --fa-style-family-classic: 'Font Awesome 6 Free'; + --fa-font-solid: normal 900 1em/1 'Font Awesome 6 Free'; } + +@font-face { + font-family: 'Font Awesome 6 Free'; + font-style: normal; + font-weight: 900; + font-display: block; + src: url("../fonts/fa-solid-900.woff2") format("woff2"), url("../fonts/fa-solid-900.ttf") format("truetype"); } + +.fas, +.fa-solid, +.content article a:where(.external-link):not(:has(img)):after { + font-weight: 900; } + +/*! + * Font Awesome Free 6.7.1 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +:root, :host { + --fa-style-family-brands: 'Font Awesome 6 Brands'; + --fa-font-brands: normal 400 1em/1 'Font Awesome 6 Brands'; } + +@font-face { + font-family: 'Font Awesome 6 Brands'; + font-style: normal; + font-weight: 400; + font-display: block; + src: url("../fonts/fa-brands-400.woff2") format("woff2"), url("../fonts/fa-brands-400.ttf") format("truetype"); } + +.fab, +.fa-brands { + font-weight: 400; } + +.fa-monero { + --fa: "\f3d0"; } + +.fa-hooli { + --fa: "\f427"; } + +.fa-yelp { + --fa: "\f1e9"; } + +.fa-cc-visa { + --fa: "\f1f0"; } + +.fa-lastfm { + --fa: "\f202"; } + +.fa-shopware { + --fa: "\f5b5"; } + +.fa-creative-commons-nc { + --fa: "\f4e8"; } + +.fa-aws { + --fa: "\f375"; } + +.fa-redhat { + --fa: "\f7bc"; } + +.fa-yoast { + --fa: "\f2b1"; } + +.fa-cloudflare { + --fa: "\e07d"; } + +.fa-ups { + --fa: "\f7e0"; } + +.fa-pixiv { + --fa: "\e640"; } + +.fa-wpexplorer { + --fa: "\f2de"; } + +.fa-dyalog { + --fa: "\f399"; } + +.fa-bity { + --fa: "\f37a"; } + +.fa-stackpath { + --fa: "\f842"; } + +.fa-buysellads { + --fa: "\f20d"; } + +.fa-first-order { + --fa: "\f2b0"; } + +.fa-modx { + --fa: "\f285"; } + +.fa-guilded { + --fa: "\e07e"; } + +.fa-vnv { + --fa: "\f40b"; } + +.fa-square-js { + --fa: "\f3b9"; } + +.fa-js-square { + --fa: "\f3b9"; } + +.fa-microsoft { + --fa: "\f3ca"; } + +.fa-qq { + --fa: "\f1d6"; } + +.fa-orcid { + --fa: "\f8d2"; } + +.fa-java { + --fa: "\f4e4"; } + +.fa-invision { + --fa: "\f7b0"; } + +.fa-creative-commons-pd-alt { + --fa: "\f4ed"; } + +.fa-centercode { + --fa: "\f380"; } + +.fa-glide-g { + --fa: "\f2a6"; } + +.fa-drupal { + --fa: "\f1a9"; } + +.fa-jxl { + --fa: "\e67b"; } + +.fa-dart-lang { + --fa: "\e693"; } + +.fa-hire-a-helper { + --fa: "\f3b0"; } + +.fa-creative-commons-by { + --fa: "\f4e7"; } + +.fa-unity { + --fa: "\e049"; } + +.fa-whmcs { + --fa: "\f40d"; } + +.fa-rocketchat { + --fa: "\f3e8"; } + +.fa-vk { + --fa: "\f189"; } + +.fa-untappd { + --fa: "\f405"; } + +.fa-mailchimp { + --fa: "\f59e"; } + +.fa-css3-alt { + --fa: "\f38b"; } + +.fa-square-reddit { + --fa: "\f1a2"; } + +.fa-reddit-square { + --fa: "\f1a2"; } + +.fa-vimeo-v { + --fa: "\f27d"; } + +.fa-contao { + --fa: "\f26d"; } + +.fa-square-font-awesome { + --fa: "\e5ad"; } + +.fa-deskpro { + --fa: "\f38f"; } + +.fa-brave { + --fa: "\e63c"; } + +.fa-sistrix { + --fa: "\f3ee"; } + +.fa-square-instagram { + --fa: "\e055"; } + +.fa-instagram-square { + --fa: "\e055"; } + +.fa-battle-net { + --fa: "\f835"; } + +.fa-the-red-yeti { + --fa: "\f69d"; } + +.fa-square-hacker-news { + --fa: "\f3af"; } + +.fa-hacker-news-square { + --fa: "\f3af"; } + +.fa-edge { + --fa: "\f282"; } + +.fa-threads { + --fa: "\e618"; } + +.fa-napster { + --fa: "\f3d2"; } + +.fa-square-snapchat { + --fa: "\f2ad"; } + +.fa-snapchat-square { + --fa: "\f2ad"; } + +.fa-google-plus-g { + --fa: "\f0d5"; } + +.fa-artstation { + --fa: "\f77a"; } + +.fa-markdown { + --fa: "\f60f"; } + +.fa-sourcetree { + --fa: "\f7d3"; } + +.fa-google-plus { + --fa: "\f2b3"; } + +.fa-diaspora { + --fa: "\f791"; } + +.fa-foursquare { + --fa: "\f180"; } + +.fa-stack-overflow { + --fa: "\f16c"; } + +.fa-github-alt { + --fa: "\f113"; } + +.fa-phoenix-squadron { + --fa: "\f511"; } + +.fa-pagelines { + --fa: "\f18c"; } + +.fa-algolia { + --fa: "\f36c"; } + +.fa-red-river { + --fa: "\f3e3"; } + +.fa-creative-commons-sa { + --fa: "\f4ef"; } + +.fa-safari { + --fa: "\f267"; } + +.fa-google { + --fa: "\f1a0"; } + +.fa-square-font-awesome-stroke { + --fa: "\f35c"; } + +.fa-font-awesome-alt { + --fa: "\f35c"; } + +.fa-atlassian { + --fa: "\f77b"; } + +.fa-linkedin-in { + --fa: "\f0e1"; } + +.fa-digital-ocean { + --fa: "\f391"; } + +.fa-nimblr { + --fa: "\f5a8"; } + +.fa-chromecast { + --fa: "\f838"; } + +.fa-evernote { + --fa: "\f839"; } + +.fa-hacker-news { + --fa: "\f1d4"; } + +.fa-creative-commons-sampling { + --fa: "\f4f0"; } + +.fa-adversal { + --fa: "\f36a"; } + +.fa-creative-commons { + --fa: "\f25e"; } + +.fa-watchman-monitoring { + --fa: "\e087"; } + +.fa-fonticons { + --fa: "\f280"; } + +.fa-weixin { + --fa: "\f1d7"; } + +.fa-shirtsinbulk { + --fa: "\f214"; } + +.fa-codepen { + --fa: "\f1cb"; } + +.fa-git-alt { + --fa: "\f841"; } + +.fa-lyft { + --fa: "\f3c3"; } + +.fa-rev { + --fa: "\f5b2"; } + +.fa-windows { + --fa: "\f17a"; } + +.fa-wizards-of-the-coast { + --fa: "\f730"; } + +.fa-square-viadeo { + --fa: "\f2aa"; } + +.fa-viadeo-square { + --fa: "\f2aa"; } + +.fa-meetup { + --fa: "\f2e0"; } + +.fa-centos { + --fa: "\f789"; } + +.fa-adn { + --fa: "\f170"; } + +.fa-cloudsmith { + --fa: "\f384"; } + +.fa-opensuse { + --fa: "\e62b"; } + +.fa-pied-piper-alt { + --fa: "\f1a8"; } + +.fa-square-dribbble { + --fa: "\f397"; } + +.fa-dribbble-square { + --fa: "\f397"; } + +.fa-codiepie { + --fa: "\f284"; } + +.fa-node { + --fa: "\f419"; } + +.fa-mix { + --fa: "\f3cb"; } + +.fa-steam { + --fa: "\f1b6"; } + +.fa-cc-apple-pay { + --fa: "\f416"; } + +.fa-scribd { + --fa: "\f28a"; } + +.fa-debian { + --fa: "\e60b"; } + +.fa-openid { + --fa: "\f19b"; } + +.fa-instalod { + --fa: "\e081"; } + +.fa-files-pinwheel { + --fa: "\e69f"; } + +.fa-expeditedssl { + --fa: "\f23e"; } + +.fa-sellcast { + --fa: "\f2da"; } + +.fa-square-twitter { + --fa: "\f081"; } + +.fa-twitter-square { + --fa: "\f081"; } + +.fa-r-project { + --fa: "\f4f7"; } + +.fa-delicious { + --fa: "\f1a5"; } + +.fa-freebsd { + --fa: "\f3a4"; } + +.fa-vuejs { + --fa: "\f41f"; } + +.fa-accusoft { + --fa: "\f369"; } + +.fa-ioxhost { + --fa: "\f208"; } + +.fa-fonticons-fi { + --fa: "\f3a2"; } + +.fa-app-store { + --fa: "\f36f"; } + +.fa-cc-mastercard { + --fa: "\f1f1"; } + +.fa-itunes-note { + --fa: "\f3b5"; } + +.fa-golang { + --fa: "\e40f"; } + +.fa-kickstarter { + --fa: "\f3bb"; } + +.fa-square-kickstarter { + --fa: "\f3bb"; } + +.fa-grav { + --fa: "\f2d6"; } + +.fa-weibo { + --fa: "\f18a"; } + +.fa-uncharted { + --fa: "\e084"; } + +.fa-firstdraft { + --fa: "\f3a1"; } + +.fa-square-youtube { + --fa: "\f431"; } + +.fa-youtube-square { + --fa: "\f431"; } + +.fa-wikipedia-w { + --fa: "\f266"; } + +.fa-wpressr { + --fa: "\f3e4"; } + +.fa-rendact { + --fa: "\f3e4"; } + +.fa-angellist { + --fa: "\f209"; } + +.fa-galactic-republic { + --fa: "\f50c"; } + +.fa-nfc-directional { + --fa: "\e530"; } + +.fa-skype { + --fa: "\f17e"; } + +.fa-joget { + --fa: "\f3b7"; } + +.fa-fedora { + --fa: "\f798"; } + +.fa-stripe-s { + --fa: "\f42a"; } + +.fa-meta { + --fa: "\e49b"; } + +.fa-laravel { + --fa: "\f3bd"; } + +.fa-hotjar { + --fa: "\f3b1"; } + +.fa-bluetooth-b { + --fa: "\f294"; } + +.fa-square-letterboxd { + --fa: "\e62e"; } + +.fa-sticker-mule { + --fa: "\f3f7"; } + +.fa-creative-commons-zero { + --fa: "\f4f3"; } + +.fa-hips { + --fa: "\f452"; } + +.fa-css { + --fa: "\e6a2"; } + +.fa-behance { + --fa: "\f1b4"; } + +.fa-reddit { + --fa: "\f1a1"; } + +.fa-discord { + --fa: "\f392"; } + +.fa-chrome { + --fa: "\f268"; } + +.fa-app-store-ios { + --fa: "\f370"; } + +.fa-cc-discover { + --fa: "\f1f2"; } + +.fa-wpbeginner { + --fa: "\f297"; } + +.fa-confluence { + --fa: "\f78d"; } + +.fa-shoelace { + --fa: "\e60c"; } + +.fa-mdb { + --fa: "\f8ca"; } + +.fa-dochub { + --fa: "\f394"; } + +.fa-accessible-icon { + --fa: "\f368"; } + +.fa-ebay { + --fa: "\f4f4"; } + +.fa-amazon { + --fa: "\f270"; } + +.fa-unsplash { + --fa: "\e07c"; } + +.fa-yarn { + --fa: "\f7e3"; } + +.fa-square-steam { + --fa: "\f1b7"; } + +.fa-steam-square { + --fa: "\f1b7"; } + +.fa-500px { + --fa: "\f26e"; } + +.fa-square-vimeo { + --fa: "\f194"; } + +.fa-vimeo-square { + --fa: "\f194"; } + +.fa-asymmetrik { + --fa: "\f372"; } + +.fa-font-awesome { + --fa: "\f2b4"; } + +.fa-font-awesome-flag { + --fa: "\f2b4"; } + +.fa-font-awesome-logo-full { + --fa: "\f2b4"; } + +.fa-gratipay { + --fa: "\f184"; } + +.fa-apple { + --fa: "\f179"; } + +.fa-hive { + --fa: "\e07f"; } + +.fa-gitkraken { + --fa: "\f3a6"; } + +.fa-keybase { + --fa: "\f4f5"; } + +.fa-apple-pay { + --fa: "\f415"; } + +.fa-padlet { + --fa: "\e4a0"; } + +.fa-amazon-pay { + --fa: "\f42c"; } + +.fa-square-github { + --fa: "\f092"; } + +.fa-github-square { + --fa: "\f092"; } + +.fa-stumbleupon { + --fa: "\f1a4"; } + +.fa-fedex { + --fa: "\f797"; } + +.fa-phoenix-framework { + --fa: "\f3dc"; } + +.fa-shopify { + --fa: "\e057"; } + +.fa-neos { + --fa: "\f612"; } + +.fa-square-threads { + --fa: "\e619"; } + +.fa-hackerrank { + --fa: "\f5f7"; } + +.fa-researchgate { + --fa: "\f4f8"; } + +.fa-swift { + --fa: "\f8e1"; } + +.fa-angular { + --fa: "\f420"; } + +.fa-speakap { + --fa: "\f3f3"; } + +.fa-angrycreative { + --fa: "\f36e"; } + +.fa-y-combinator { + --fa: "\f23b"; } + +.fa-empire { + --fa: "\f1d1"; } + +.fa-envira { + --fa: "\f299"; } + +.fa-google-scholar { + --fa: "\e63b"; } + +.fa-square-gitlab { + --fa: "\e5ae"; } + +.fa-gitlab-square { + --fa: "\e5ae"; } + +.fa-studiovinari { + --fa: "\f3f8"; } + +.fa-pied-piper { + --fa: "\f2ae"; } + +.fa-wordpress { + --fa: "\f19a"; } + +.fa-product-hunt { + --fa: "\f288"; } + +.fa-firefox { + --fa: "\f269"; } + +.fa-linode { + --fa: "\f2b8"; } + +.fa-goodreads { + --fa: "\f3a8"; } + +.fa-square-odnoklassniki { + --fa: "\f264"; } + +.fa-odnoklassniki-square { + --fa: "\f264"; } + +.fa-jsfiddle { + --fa: "\f1cc"; } + +.fa-sith { + --fa: "\f512"; } + +.fa-themeisle { + --fa: "\f2b2"; } + +.fa-page4 { + --fa: "\f3d7"; } + +.fa-hashnode { + --fa: "\e499"; } + +.fa-react { + --fa: "\f41b"; } + +.fa-cc-paypal { + --fa: "\f1f4"; } + +.fa-squarespace { + --fa: "\f5be"; } + +.fa-cc-stripe { + --fa: "\f1f5"; } + +.fa-creative-commons-share { + --fa: "\f4f2"; } + +.fa-bitcoin { + --fa: "\f379"; } + +.fa-keycdn { + --fa: "\f3ba"; } + +.fa-opera { + --fa: "\f26a"; } + +.fa-itch-io { + --fa: "\f83a"; } + +.fa-umbraco { + --fa: "\f8e8"; } + +.fa-galactic-senate { + --fa: "\f50d"; } + +.fa-ubuntu { + --fa: "\f7df"; } + +.fa-draft2digital { + --fa: "\f396"; } + +.fa-stripe { + --fa: "\f429"; } + +.fa-houzz { + --fa: "\f27c"; } + +.fa-gg { + --fa: "\f260"; } + +.fa-dhl { + --fa: "\f790"; } + +.fa-square-pinterest { + --fa: "\f0d3"; } + +.fa-pinterest-square { + --fa: "\f0d3"; } + +.fa-xing { + --fa: "\f168"; } + +.fa-blackberry { + --fa: "\f37b"; } + +.fa-creative-commons-pd { + --fa: "\f4ec"; } + +.fa-playstation { + --fa: "\f3df"; } + +.fa-quinscape { + --fa: "\f459"; } + +.fa-less { + --fa: "\f41d"; } + +.fa-blogger-b { + --fa: "\f37d"; } + +.fa-opencart { + --fa: "\f23d"; } + +.fa-vine { + --fa: "\f1ca"; } + +.fa-signal-messenger { + --fa: "\e663"; } + +.fa-paypal { + --fa: "\f1ed"; } + +.fa-gitlab { + --fa: "\f296"; } + +.fa-typo3 { + --fa: "\f42b"; } + +.fa-reddit-alien { + --fa: "\f281"; } + +.fa-yahoo { + --fa: "\f19e"; } + +.fa-dailymotion { + --fa: "\e052"; } + +.fa-affiliatetheme { + --fa: "\f36b"; } + +.fa-pied-piper-pp { + --fa: "\f1a7"; } + +.fa-bootstrap { + --fa: "\f836"; } + +.fa-odnoklassniki { + --fa: "\f263"; } + +.fa-nfc-symbol { + --fa: "\e531"; } + +.fa-mintbit { + --fa: "\e62f"; } + +.fa-ethereum { + --fa: "\f42e"; } + +.fa-speaker-deck { + --fa: "\f83c"; } + +.fa-creative-commons-nc-eu { + --fa: "\f4e9"; } + +.fa-patreon { + --fa: "\f3d9"; } + +.fa-avianex { + --fa: "\f374"; } + +.fa-ello { + --fa: "\f5f1"; } + +.fa-gofore { + --fa: "\f3a7"; } + +.fa-bimobject { + --fa: "\f378"; } + +.fa-brave-reverse { + --fa: "\e63d"; } + +.fa-facebook-f { + --fa: "\f39e"; } + +.fa-square-google-plus { + --fa: "\f0d4"; } + +.fa-google-plus-square { + --fa: "\f0d4"; } + +.fa-web-awesome { + --fa: "\e682"; } + +.fa-mandalorian { + --fa: "\f50f"; } + +.fa-first-order-alt { + --fa: "\f50a"; } + +.fa-osi { + --fa: "\f41a"; } + +.fa-google-wallet { + --fa: "\f1ee"; } + +.fa-d-and-d-beyond { + --fa: "\f6ca"; } + +.fa-periscope { + --fa: "\f3da"; } + +.fa-fulcrum { + --fa: "\f50b"; } + +.fa-cloudscale { + --fa: "\f383"; } + +.fa-forumbee { + --fa: "\f211"; } + +.fa-mizuni { + --fa: "\f3cc"; } + +.fa-schlix { + --fa: "\f3ea"; } + +.fa-square-xing { + --fa: "\f169"; } + +.fa-xing-square { + --fa: "\f169"; } + +.fa-bandcamp { + --fa: "\f2d5"; } + +.fa-wpforms { + --fa: "\f298"; } + +.fa-cloudversify { + --fa: "\f385"; } + +.fa-usps { + --fa: "\f7e1"; } + +.fa-megaport { + --fa: "\f5a3"; } + +.fa-magento { + --fa: "\f3c4"; } + +.fa-spotify { + --fa: "\f1bc"; } + +.fa-optin-monster { + --fa: "\f23c"; } + +.fa-fly { + --fa: "\f417"; } + +.fa-square-bluesky { + --fa: "\e6a3"; } + +.fa-aviato { + --fa: "\f421"; } + +.fa-itunes { + --fa: "\f3b4"; } + +.fa-cuttlefish { + --fa: "\f38c"; } + +.fa-blogger { + --fa: "\f37c"; } + +.fa-flickr { + --fa: "\f16e"; } + +.fa-viber { + --fa: "\f409"; } + +.fa-soundcloud { + --fa: "\f1be"; } + +.fa-digg { + --fa: "\f1a6"; } + +.fa-tencent-weibo { + --fa: "\f1d5"; } + +.fa-letterboxd { + --fa: "\e62d"; } + +.fa-symfony { + --fa: "\f83d"; } + +.fa-maxcdn { + --fa: "\f136"; } + +.fa-etsy { + --fa: "\f2d7"; } + +.fa-facebook-messenger { + --fa: "\f39f"; } + +.fa-audible { + --fa: "\f373"; } + +.fa-think-peaks { + --fa: "\f731"; } + +.fa-bilibili { + --fa: "\e3d9"; } + +.fa-erlang { + --fa: "\f39d"; } + +.fa-x-twitter { + --fa: "\e61b"; } + +.fa-cotton-bureau { + --fa: "\f89e"; } + +.fa-dashcube { + --fa: "\f210"; } + +.fa-42-group { + --fa: "\e080"; } + +.fa-innosoft { + --fa: "\e080"; } + +.fa-stack-exchange { + --fa: "\f18d"; } + +.fa-elementor { + --fa: "\f430"; } + +.fa-square-pied-piper { + --fa: "\e01e"; } + +.fa-pied-piper-square { + --fa: "\e01e"; } + +.fa-creative-commons-nd { + --fa: "\f4eb"; } + +.fa-palfed { + --fa: "\f3d8"; } + +.fa-superpowers { + --fa: "\f2dd"; } + +.fa-resolving { + --fa: "\f3e7"; } + +.fa-xbox { + --fa: "\f412"; } + +.fa-square-web-awesome-stroke { + --fa: "\e684"; } + +.fa-searchengin { + --fa: "\f3eb"; } + +.fa-tiktok { + --fa: "\e07b"; } + +.fa-square-facebook { + --fa: "\f082"; } + +.fa-facebook-square { + --fa: "\f082"; } + +.fa-renren { + --fa: "\f18b"; } + +.fa-linux { + --fa: "\f17c"; } + +.fa-glide { + --fa: "\f2a5"; } + +.fa-linkedin { + --fa: "\f08c"; } + +.fa-hubspot { + --fa: "\f3b2"; } + +.fa-deploydog { + --fa: "\f38e"; } + +.fa-twitch { + --fa: "\f1e8"; } + +.fa-flutter { + --fa: "\e694"; } + +.fa-ravelry { + --fa: "\f2d9"; } + +.fa-mixer { + --fa: "\e056"; } + +.fa-square-lastfm { + --fa: "\f203"; } + +.fa-lastfm-square { + --fa: "\f203"; } + +.fa-vimeo { + --fa: "\f40a"; } + +.fa-mendeley { + --fa: "\f7b3"; } + +.fa-uniregistry { + --fa: "\f404"; } + +.fa-figma { + --fa: "\f799"; } + +.fa-creative-commons-remix { + --fa: "\f4ee"; } + +.fa-cc-amazon-pay { + --fa: "\f42d"; } + +.fa-dropbox { + --fa: "\f16b"; } + +.fa-instagram { + --fa: "\f16d"; } + +.fa-cmplid { + --fa: "\e360"; } + +.fa-upwork { + --fa: "\e641"; } + +.fa-facebook { + --fa: "\f09a"; } + +.fa-gripfire { + --fa: "\f3ac"; } + +.fa-jedi-order { + --fa: "\f50e"; } + +.fa-uikit { + --fa: "\f403"; } + +.fa-fort-awesome-alt { + --fa: "\f3a3"; } + +.fa-phabricator { + --fa: "\f3db"; } + +.fa-ussunnah { + --fa: "\f407"; } + +.fa-earlybirds { + --fa: "\f39a"; } + +.fa-trade-federation { + --fa: "\f513"; } + +.fa-autoprefixer { + --fa: "\f41c"; } + +.fa-whatsapp { + --fa: "\f232"; } + +.fa-square-upwork { + --fa: "\e67c"; } + +.fa-slideshare { + --fa: "\f1e7"; } + +.fa-google-play { + --fa: "\f3ab"; } + +.fa-viadeo { + --fa: "\f2a9"; } + +.fa-line { + --fa: "\f3c0"; } + +.fa-google-drive { + --fa: "\f3aa"; } + +.fa-servicestack { + --fa: "\f3ec"; } + +.fa-simplybuilt { + --fa: "\f215"; } + +.fa-bitbucket { + --fa: "\f171"; } + +.fa-imdb { + --fa: "\f2d8"; } + +.fa-deezer { + --fa: "\e077"; } + +.fa-raspberry-pi { + --fa: "\f7bb"; } + +.fa-jira { + --fa: "\f7b1"; } + +.fa-docker { + --fa: "\f395"; } + +.fa-screenpal { + --fa: "\e570"; } + +.fa-bluetooth { + --fa: "\f293"; } + +.fa-gitter { + --fa: "\f426"; } + +.fa-d-and-d { + --fa: "\f38d"; } + +.fa-microblog { + --fa: "\e01a"; } + +.fa-cc-diners-club { + --fa: "\f24c"; } + +.fa-gg-circle { + --fa: "\f261"; } + +.fa-pied-piper-hat { + --fa: "\f4e5"; } + +.fa-kickstarter-k { + --fa: "\f3bc"; } + +.fa-yandex { + --fa: "\f413"; } + +.fa-readme { + --fa: "\f4d5"; } + +.fa-html5 { + --fa: "\f13b"; } + +.fa-sellsy { + --fa: "\f213"; } + +.fa-square-web-awesome { + --fa: "\e683"; } + +.fa-sass { + --fa: "\f41e"; } + +.fa-wirsindhandwerk { + --fa: "\e2d0"; } + +.fa-wsh { + --fa: "\e2d0"; } + +.fa-buromobelexperte { + --fa: "\f37f"; } + +.fa-salesforce { + --fa: "\f83b"; } + +.fa-octopus-deploy { + --fa: "\e082"; } + +.fa-medapps { + --fa: "\f3c6"; } + +.fa-ns8 { + --fa: "\f3d5"; } + +.fa-pinterest-p { + --fa: "\f231"; } + +.fa-apper { + --fa: "\f371"; } + +.fa-fort-awesome { + --fa: "\f286"; } + +.fa-waze { + --fa: "\f83f"; } + +.fa-bluesky { + --fa: "\e671"; } + +.fa-cc-jcb { + --fa: "\f24b"; } + +.fa-snapchat { + --fa: "\f2ab"; } + +.fa-snapchat-ghost { + --fa: "\f2ab"; } + +.fa-fantasy-flight-games { + --fa: "\f6dc"; } + +.fa-rust { + --fa: "\e07a"; } + +.fa-wix { + --fa: "\f5cf"; } + +.fa-square-behance { + --fa: "\f1b5"; } + +.fa-behance-square { + --fa: "\f1b5"; } + +.fa-supple { + --fa: "\f3f9"; } + +.fa-webflow { + --fa: "\e65c"; } + +.fa-rebel { + --fa: "\f1d0"; } + +.fa-css3 { + --fa: "\f13c"; } + +.fa-staylinked { + --fa: "\f3f5"; } + +.fa-kaggle { + --fa: "\f5fa"; } + +.fa-space-awesome { + --fa: "\e5ac"; } + +.fa-deviantart { + --fa: "\f1bd"; } + +.fa-cpanel { + --fa: "\f388"; } + +.fa-goodreads-g { + --fa: "\f3a9"; } + +.fa-square-git { + --fa: "\f1d2"; } + +.fa-git-square { + --fa: "\f1d2"; } + +.fa-square-tumblr { + --fa: "\f174"; } + +.fa-tumblr-square { + --fa: "\f174"; } + +.fa-trello { + --fa: "\f181"; } + +.fa-creative-commons-nc-jp { + --fa: "\f4ea"; } + +.fa-get-pocket { + --fa: "\f265"; } + +.fa-perbyte { + --fa: "\e083"; } + +.fa-grunt { + --fa: "\f3ad"; } + +.fa-weebly { + --fa: "\f5cc"; } + +.fa-connectdevelop { + --fa: "\f20e"; } + +.fa-leanpub { + --fa: "\f212"; } + +.fa-black-tie { + --fa: "\f27e"; } + +.fa-themeco { + --fa: "\f5c6"; } + +.fa-python { + --fa: "\f3e2"; } + +.fa-android { + --fa: "\f17b"; } + +.fa-bots { + --fa: "\e340"; } + +.fa-free-code-camp { + --fa: "\f2c5"; } + +.fa-hornbill { + --fa: "\f592"; } + +.fa-js { + --fa: "\f3b8"; } + +.fa-ideal { + --fa: "\e013"; } + +.fa-git { + --fa: "\f1d3"; } + +.fa-dev { + --fa: "\f6cc"; } + +.fa-sketch { + --fa: "\f7c6"; } + +.fa-yandex-international { + --fa: "\f414"; } + +.fa-cc-amex { + --fa: "\f1f3"; } + +.fa-uber { + --fa: "\f402"; } + +.fa-github { + --fa: "\f09b"; } + +.fa-php { + --fa: "\f457"; } + +.fa-alipay { + --fa: "\f642"; } + +.fa-youtube { + --fa: "\f167"; } + +.fa-skyatlas { + --fa: "\f216"; } + +.fa-firefox-browser { + --fa: "\e007"; } + +.fa-replyd { + --fa: "\f3e6"; } + +.fa-suse { + --fa: "\f7d6"; } + +.fa-jenkins { + --fa: "\f3b6"; } + +.fa-twitter { + --fa: "\f099"; } + +.fa-rockrms { + --fa: "\f3e9"; } + +.fa-pinterest { + --fa: "\f0d2"; } + +.fa-buffer { + --fa: "\f837"; } + +.fa-npm { + --fa: "\f3d4"; } + +.fa-yammer { + --fa: "\f840"; } + +.fa-btc { + --fa: "\f15a"; } + +.fa-dribbble { + --fa: "\f17d"; } + +.fa-stumbleupon-circle { + --fa: "\f1a3"; } + +.fa-internet-explorer { + --fa: "\f26b"; } + +.fa-stubber { + --fa: "\e5c7"; } + +.fa-telegram { + --fa: "\f2c6"; } + +.fa-telegram-plane { + --fa: "\f2c6"; } + +.fa-old-republic { + --fa: "\f510"; } + +.fa-odysee { + --fa: "\e5c6"; } + +.fa-square-whatsapp { + --fa: "\f40c"; } + +.fa-whatsapp-square { + --fa: "\f40c"; } + +.fa-node-js { + --fa: "\f3d3"; } + +.fa-edge-legacy { + --fa: "\e078"; } + +.fa-slack { + --fa: "\f198"; } + +.fa-slack-hash { + --fa: "\f198"; } + +.fa-medrt { + --fa: "\f3c8"; } + +.fa-usb { + --fa: "\f287"; } + +.fa-tumblr { + --fa: "\f173"; } + +.fa-vaadin { + --fa: "\f408"; } + +.fa-quora { + --fa: "\f2c4"; } + +.fa-square-x-twitter { + --fa: "\e61a"; } + +.fa-reacteurope { + --fa: "\f75d"; } + +.fa-medium { + --fa: "\f23a"; } + +.fa-medium-m { + --fa: "\f23a"; } + +.fa-amilia { + --fa: "\f36d"; } + +.fa-mixcloud { + --fa: "\f289"; } + +.fa-flipboard { + --fa: "\f44d"; } + +.fa-viacoin { + --fa: "\f237"; } + +.fa-critical-role { + --fa: "\f6c9"; } + +.fa-sitrox { + --fa: "\e44a"; } + +.fa-discourse { + --fa: "\f393"; } + +.fa-joomla { + --fa: "\f1aa"; } + +.fa-mastodon { + --fa: "\f4f6"; } + +.fa-airbnb { + --fa: "\f834"; } + +.fa-wolf-pack-battalion { + --fa: "\f514"; } + +.fa-buy-n-large { + --fa: "\f8a6"; } + +.fa-gulp { + --fa: "\f3ae"; } + +.fa-creative-commons-sampling-plus { + --fa: "\f4f1"; } + +.fa-strava { + --fa: "\f428"; } + +.fa-ember { + --fa: "\f423"; } + +.fa-canadian-maple-leaf { + --fa: "\f785"; } + +.fa-teamspeak { + --fa: "\f4f9"; } + +.fa-pushed { + --fa: "\f3e1"; } + +.fa-wordpress-simple { + --fa: "\f411"; } + +.fa-nutritionix { + --fa: "\f3d6"; } + +.fa-wodu { + --fa: "\e088"; } + +.fa-google-pay { + --fa: "\e079"; } + +.fa-intercom { + --fa: "\f7af"; } + +.fa-zhihu { + --fa: "\f63f"; } + +.fa-korvue { + --fa: "\f42f"; } + +.fa-pix { + --fa: "\e43a"; } + +.fa-steam-symbol { + --fa: "\f3f6"; } + +/*! + * Font Awesome Free 6.7.1 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +.fa.fa-glass { + --fa: "\f000"; } + +.fa.fa-envelope-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-envelope-o { + --fa: "\f0e0"; } + +.fa.fa-star-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-star-o { + --fa: "\f005"; } + +.fa.fa-remove { + --fa: "\f00d"; } + +.fa.fa-close { + --fa: "\f00d"; } + +.fa.fa-gear { + --fa: "\f013"; } + +.fa.fa-trash-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-trash-o { + --fa: "\f2ed"; } + +.fa.fa-home { + --fa: "\f015"; } + +.fa.fa-file-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-o { + --fa: "\f15b"; } + +.fa.fa-clock-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-clock-o { + --fa: "\f017"; } + +.fa.fa-arrow-circle-o-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-down { + --fa: "\f358"; } + +.fa.fa-arrow-circle-o-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-up { + --fa: "\f35b"; } + +.fa.fa-play-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-play-circle-o { + --fa: "\f144"; } + +.fa.fa-repeat { + --fa: "\f01e"; } + +.fa.fa-rotate-right { + --fa: "\f01e"; } + +.fa.fa-refresh { + --fa: "\f021"; } + +.fa.fa-list-alt { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-list-alt { + --fa: "\f022"; } + +.fa.fa-dedent { + --fa: "\f03b"; } + +.fa.fa-video-camera { + --fa: "\f03d"; } + +.fa.fa-picture-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-picture-o { + --fa: "\f03e"; } + +.fa.fa-photo { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-photo { + --fa: "\f03e"; } + +.fa.fa-image { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-image { + --fa: "\f03e"; } + +.fa.fa-map-marker { + --fa: "\f3c5"; } + +.fa.fa-pencil-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-pencil-square-o { + --fa: "\f044"; } + +.fa.fa-edit { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-edit { + --fa: "\f044"; } + +.fa.fa-share-square-o { + --fa: "\f14d"; } + +.fa.fa-check-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-check-square-o { + --fa: "\f14a"; } + +.fa.fa-arrows { + --fa: "\f0b2"; } + +.fa.fa-times-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-times-circle-o { + --fa: "\f057"; } + +.fa.fa-check-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-check-circle-o { + --fa: "\f058"; } + +.fa.fa-mail-forward { + --fa: "\f064"; } + +.fa.fa-expand { + --fa: "\f424"; } + +.fa.fa-compress { + --fa: "\f422"; } + +.fa.fa-eye { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-eye-slash { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-warning { + --fa: "\f071"; } + +.fa.fa-calendar { + --fa: "\f073"; } + +.fa.fa-arrows-v { + --fa: "\f338"; } + +.fa.fa-arrows-h { + --fa: "\f337"; } + +.fa.fa-bar-chart { + --fa: "\e0e3"; } + +.fa.fa-bar-chart-o { + --fa: "\e0e3"; } + +.fa.fa-twitter-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-twitter-square { + --fa: "\f081"; } + +.fa.fa-facebook-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-facebook-square { + --fa: "\f082"; } + +.fa.fa-gears { + --fa: "\f085"; } + +.fa.fa-thumbs-o-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-thumbs-o-up { + --fa: "\f164"; } + +.fa.fa-thumbs-o-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-thumbs-o-down { + --fa: "\f165"; } + +.fa.fa-heart-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-heart-o { + --fa: "\f004"; } + +.fa.fa-sign-out { + --fa: "\f2f5"; } + +.fa.fa-linkedin-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-linkedin-square { + --fa: "\f08c"; } + +.fa.fa-thumb-tack { + --fa: "\f08d"; } + +.fa.fa-external-link { + --fa: "\f35d"; } + +.fa.fa-sign-in { + --fa: "\f2f6"; } + +.fa.fa-github-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-github-square { + --fa: "\f092"; } + +.fa.fa-lemon-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-lemon-o { + --fa: "\f094"; } + +.fa.fa-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-square-o { + --fa: "\f0c8"; } + +.fa.fa-bookmark-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-bookmark-o { + --fa: "\f02e"; } + +.fa.fa-twitter { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-facebook { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-facebook { + --fa: "\f39e"; } + +.fa.fa-facebook-f { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-facebook-f { + --fa: "\f39e"; } + +.fa.fa-github { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-credit-card { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-feed { + --fa: "\f09e"; } + +.fa.fa-hdd-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hdd-o { + --fa: "\f0a0"; } + +.fa.fa-hand-o-right { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-o-right { + --fa: "\f0a4"; } + +.fa.fa-hand-o-left { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-o-left { + --fa: "\f0a5"; } + +.fa.fa-hand-o-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-o-up { + --fa: "\f0a6"; } + +.fa.fa-hand-o-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-o-down { + --fa: "\f0a7"; } + +.fa.fa-globe { + --fa: "\f57d"; } + +.fa.fa-tasks { + --fa: "\f828"; } + +.fa.fa-arrows-alt { + --fa: "\f31e"; } + +.fa.fa-group { + --fa: "\f0c0"; } + +.fa.fa-chain { + --fa: "\f0c1"; } + +.fa.fa-cut { + --fa: "\f0c4"; } + +.fa.fa-files-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-files-o { + --fa: "\f0c5"; } + +.fa.fa-floppy-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-floppy-o { + --fa: "\f0c7"; } + +.fa.fa-save { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-save { + --fa: "\f0c7"; } + +.fa.fa-navicon { + --fa: "\f0c9"; } + +.fa.fa-reorder { + --fa: "\f0c9"; } + +.fa.fa-magic { + --fa: "\e2ca"; } + +.fa.fa-pinterest { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pinterest-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pinterest-square { + --fa: "\f0d3"; } + +.fa.fa-google-plus-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-plus-square { + --fa: "\f0d4"; } + +.fa.fa-google-plus { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-plus { + --fa: "\f0d5"; } + +.fa.fa-money { + --fa: "\f3d1"; } + +.fa.fa-unsorted { + --fa: "\f0dc"; } + +.fa.fa-sort-desc { + --fa: "\f0dd"; } + +.fa.fa-sort-asc { + --fa: "\f0de"; } + +.fa.fa-linkedin { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-linkedin { + --fa: "\f0e1"; } + +.fa.fa-rotate-left { + --fa: "\f0e2"; } + +.fa.fa-legal { + --fa: "\f0e3"; } + +.fa.fa-tachometer { + --fa: "\f625"; } + +.fa.fa-dashboard { + --fa: "\f625"; } + +.fa.fa-comment-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-comment-o { + --fa: "\f075"; } + +.fa.fa-comments-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-comments-o { + --fa: "\f086"; } + +.fa.fa-flash { + --fa: "\f0e7"; } + +.fa.fa-clipboard { + --fa: "\f0ea"; } + +.fa.fa-lightbulb-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-lightbulb-o { + --fa: "\f0eb"; } + +.fa.fa-exchange { + --fa: "\f362"; } + +.fa.fa-cloud-download { + --fa: "\f0ed"; } + +.fa.fa-cloud-upload { + --fa: "\f0ee"; } + +.fa.fa-bell-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-bell-o { + --fa: "\f0f3"; } + +.fa.fa-cutlery { + --fa: "\f2e7"; } + +.fa.fa-file-text-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-text-o { + --fa: "\f15c"; } + +.fa.fa-building-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-building-o { + --fa: "\f1ad"; } + +.fa.fa-hospital-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hospital-o { + --fa: "\f0f8"; } + +.fa.fa-tablet { + --fa: "\f3fa"; } + +.fa.fa-mobile { + --fa: "\f3cd"; } + +.fa.fa-mobile-phone { + --fa: "\f3cd"; } + +.fa.fa-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-circle-o { + --fa: "\f111"; } + +.fa.fa-mail-reply { + --fa: "\f3e5"; } + +.fa.fa-github-alt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-folder-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-folder-o { + --fa: "\f07b"; } + +.fa.fa-folder-open-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-folder-open-o { + --fa: "\f07c"; } + +.fa.fa-smile-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-smile-o { + --fa: "\f118"; } + +.fa.fa-frown-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-frown-o { + --fa: "\f119"; } + +.fa.fa-meh-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-meh-o { + --fa: "\f11a"; } + +.fa.fa-keyboard-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-keyboard-o { + --fa: "\f11c"; } + +.fa.fa-flag-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-flag-o { + --fa: "\f024"; } + +.fa.fa-mail-reply-all { + --fa: "\f122"; } + +.fa.fa-star-half-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-star-half-o { + --fa: "\f5c0"; } + +.fa.fa-star-half-empty { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-star-half-empty { + --fa: "\f5c0"; } + +.fa.fa-star-half-full { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-star-half-full { + --fa: "\f5c0"; } + +.fa.fa-code-fork { + --fa: "\f126"; } + +.fa.fa-chain-broken { + --fa: "\f127"; } + +.fa.fa-unlink { + --fa: "\f127"; } + +.fa.fa-calendar-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-calendar-o { + --fa: "\f133"; } + +.fa.fa-maxcdn { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-html5 { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-css3 { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-unlock-alt { + --fa: "\f09c"; } + +.fa.fa-minus-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-minus-square-o { + --fa: "\f146"; } + +.fa.fa-level-up { + --fa: "\f3bf"; } + +.fa.fa-level-down { + --fa: "\f3be"; } + +.fa.fa-pencil-square { + --fa: "\f14b"; } + +.fa.fa-external-link-square { + --fa: "\f360"; } + +.fa.fa-compass { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-down { + --fa: "\f150"; } + +.fa.fa-toggle-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-toggle-down { + --fa: "\f150"; } + +.fa.fa-caret-square-o-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-up { + --fa: "\f151"; } + +.fa.fa-toggle-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-toggle-up { + --fa: "\f151"; } + +.fa.fa-caret-square-o-right { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-right { + --fa: "\f152"; } + +.fa.fa-toggle-right { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-toggle-right { + --fa: "\f152"; } + +.fa.fa-eur { + --fa: "\f153"; } + +.fa.fa-euro { + --fa: "\f153"; } + +.fa.fa-gbp { + --fa: "\f154"; } + +.fa.fa-usd { + --fa: "\24"; } + +.fa.fa-dollar { + --fa: "\24"; } + +.fa.fa-inr { + --fa: "\e1bc"; } + +.fa.fa-rupee { + --fa: "\e1bc"; } + +.fa.fa-jpy { + --fa: "\f157"; } + +.fa.fa-cny { + --fa: "\f157"; } + +.fa.fa-rmb { + --fa: "\f157"; } + +.fa.fa-yen { + --fa: "\f157"; } + +.fa.fa-rub { + --fa: "\f158"; } + +.fa.fa-ruble { + --fa: "\f158"; } + +.fa.fa-rouble { + --fa: "\f158"; } + +.fa.fa-krw { + --fa: "\f159"; } + +.fa.fa-won { + --fa: "\f159"; } + +.fa.fa-btc { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bitcoin { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bitcoin { + --fa: "\f15a"; } + +.fa.fa-file-text { + --fa: "\f15c"; } + +.fa.fa-sort-alpha-asc { + --fa: "\f15d"; } + +.fa.fa-sort-alpha-desc { + --fa: "\f881"; } + +.fa.fa-sort-amount-asc { + --fa: "\f884"; } + +.fa.fa-sort-amount-desc { + --fa: "\f160"; } + +.fa.fa-sort-numeric-asc { + --fa: "\f162"; } + +.fa.fa-sort-numeric-desc { + --fa: "\f886"; } + +.fa.fa-youtube-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-youtube-square { + --fa: "\f431"; } + +.fa.fa-youtube { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-xing { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-xing-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-xing-square { + --fa: "\f169"; } + +.fa.fa-youtube-play { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-youtube-play { + --fa: "\f167"; } + +.fa.fa-dropbox { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-stack-overflow { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-instagram { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-flickr { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-adn { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bitbucket { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bitbucket-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bitbucket-square { + --fa: "\f171"; } + +.fa.fa-tumblr { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-tumblr-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-tumblr-square { + --fa: "\f174"; } + +.fa.fa-long-arrow-down { + --fa: "\f309"; } + +.fa.fa-long-arrow-up { + --fa: "\f30c"; } + +.fa.fa-long-arrow-left { + --fa: "\f30a"; } + +.fa.fa-long-arrow-right { + --fa: "\f30b"; } + +.fa.fa-apple { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-windows { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-android { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-linux { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-dribbble { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-skype { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-foursquare { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-trello { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gratipay { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gittip { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gittip { + --fa: "\f184"; } + +.fa.fa-sun-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-sun-o { + --fa: "\f185"; } + +.fa.fa-moon-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-moon-o { + --fa: "\f186"; } + +.fa.fa-vk { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-weibo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-renren { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pagelines { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-stack-exchange { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-right { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-right { + --fa: "\f35a"; } + +.fa.fa-arrow-circle-o-left { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-left { + --fa: "\f359"; } + +.fa.fa-caret-square-o-left { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-left { + --fa: "\f191"; } + +.fa.fa-toggle-left { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-toggle-left { + --fa: "\f191"; } + +.fa.fa-dot-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-dot-circle-o { + --fa: "\f192"; } + +.fa.fa-vimeo-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-vimeo-square { + --fa: "\f194"; } + +.fa.fa-try { + --fa: "\e2bb"; } + +.fa.fa-turkish-lira { + --fa: "\e2bb"; } + +.fa.fa-plus-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-plus-square-o { + --fa: "\f0fe"; } + +.fa.fa-slack { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wordpress { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-openid { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-institution { + --fa: "\f19c"; } + +.fa.fa-bank { + --fa: "\f19c"; } + +.fa.fa-mortar-board { + --fa: "\f19d"; } + +.fa.fa-yahoo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-reddit { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-reddit-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-reddit-square { + --fa: "\f1a2"; } + +.fa.fa-stumbleupon-circle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-stumbleupon { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-delicious { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-digg { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pied-piper-pp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pied-piper-alt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-drupal { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-joomla { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-behance { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-behance-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-behance-square { + --fa: "\f1b5"; } + +.fa.fa-steam { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-steam-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-steam-square { + --fa: "\f1b7"; } + +.fa.fa-automobile { + --fa: "\f1b9"; } + +.fa.fa-cab { + --fa: "\f1ba"; } + +.fa.fa-spotify { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-deviantart { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-soundcloud { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-file-pdf-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-pdf-o { + --fa: "\f1c1"; } + +.fa.fa-file-word-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-word-o { + --fa: "\f1c2"; } + +.fa.fa-file-excel-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-excel-o { + --fa: "\f1c3"; } + +.fa.fa-file-powerpoint-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-powerpoint-o { + --fa: "\f1c4"; } + +.fa.fa-file-image-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-image-o { + --fa: "\f1c5"; } + +.fa.fa-file-photo-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-photo-o { + --fa: "\f1c5"; } + +.fa.fa-file-picture-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-picture-o { + --fa: "\f1c5"; } + +.fa.fa-file-archive-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-archive-o { + --fa: "\f1c6"; } + +.fa.fa-file-zip-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-zip-o { + --fa: "\f1c6"; } + +.fa.fa-file-audio-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-audio-o { + --fa: "\f1c7"; } + +.fa.fa-file-sound-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-sound-o { + --fa: "\f1c7"; } + +.fa.fa-file-video-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-video-o { + --fa: "\f1c8"; } + +.fa.fa-file-movie-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-movie-o { + --fa: "\f1c8"; } + +.fa.fa-file-code-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-code-o { + --fa: "\f1c9"; } + +.fa.fa-vine { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-codepen { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-jsfiddle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-life-bouy { + --fa: "\f1cd"; } + +.fa.fa-life-buoy { + --fa: "\f1cd"; } + +.fa.fa-life-saver { + --fa: "\f1cd"; } + +.fa.fa-support { + --fa: "\f1cd"; } + +.fa.fa-circle-o-notch { + --fa: "\f1ce"; } + +.fa.fa-rebel { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-ra { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-ra { + --fa: "\f1d0"; } + +.fa.fa-resistance { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-resistance { + --fa: "\f1d0"; } + +.fa.fa-empire { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-ge { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-ge { + --fa: "\f1d1"; } + +.fa.fa-git-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-git-square { + --fa: "\f1d2"; } + +.fa.fa-git { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-hacker-news { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-y-combinator-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-y-combinator-square { + --fa: "\f1d4"; } + +.fa.fa-yc-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-yc-square { + --fa: "\f1d4"; } + +.fa.fa-tencent-weibo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-qq { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-weixin { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wechat { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wechat { + --fa: "\f1d7"; } + +.fa.fa-send { + --fa: "\f1d8"; } + +.fa.fa-paper-plane-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-paper-plane-o { + --fa: "\f1d8"; } + +.fa.fa-send-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-send-o { + --fa: "\f1d8"; } + +.fa.fa-circle-thin { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-circle-thin { + --fa: "\f111"; } + +.fa.fa-header { + --fa: "\f1dc"; } + +.fa.fa-futbol-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-futbol-o { + --fa: "\f1e3"; } + +.fa.fa-soccer-ball-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-soccer-ball-o { + --fa: "\f1e3"; } + +.fa.fa-slideshare { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-twitch { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-yelp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-newspaper-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-newspaper-o { + --fa: "\f1ea"; } + +.fa.fa-paypal { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-wallet { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-visa { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-mastercard { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-discover { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-amex { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-paypal { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-stripe { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bell-slash-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-bell-slash-o { + --fa: "\f1f6"; } + +.fa.fa-trash { + --fa: "\f2ed"; } + +.fa.fa-copyright { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-eyedropper { + --fa: "\f1fb"; } + +.fa.fa-area-chart { + --fa: "\f1fe"; } + +.fa.fa-pie-chart { + --fa: "\f200"; } + +.fa.fa-line-chart { + --fa: "\f201"; } + +.fa.fa-lastfm { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-lastfm-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-lastfm-square { + --fa: "\f203"; } + +.fa.fa-ioxhost { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-angellist { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-cc { + --fa: "\f20a"; } + +.fa.fa-ils { + --fa: "\f20b"; } + +.fa.fa-shekel { + --fa: "\f20b"; } + +.fa.fa-sheqel { + --fa: "\f20b"; } + +.fa.fa-buysellads { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-connectdevelop { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-dashcube { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-forumbee { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-leanpub { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-sellsy { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-shirtsinbulk { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-simplybuilt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-skyatlas { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-diamond { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-diamond { + --fa: "\f3a5"; } + +.fa.fa-transgender { + --fa: "\f224"; } + +.fa.fa-intersex { + --fa: "\f224"; } + +.fa.fa-transgender-alt { + --fa: "\f225"; } + +.fa.fa-facebook-official { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-facebook-official { + --fa: "\f09a"; } + +.fa.fa-pinterest-p { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-whatsapp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-hotel { + --fa: "\f236"; } + +.fa.fa-viacoin { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-medium { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-y-combinator { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-yc { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-yc { + --fa: "\f23b"; } + +.fa.fa-optin-monster { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-opencart { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-expeditedssl { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-battery-4 { + --fa: "\f240"; } + +.fa.fa-battery { + --fa: "\f240"; } + +.fa.fa-battery-3 { + --fa: "\f241"; } + +.fa.fa-battery-2 { + --fa: "\f242"; } + +.fa.fa-battery-1 { + --fa: "\f243"; } + +.fa.fa-battery-0 { + --fa: "\f244"; } + +.fa.fa-object-group { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-object-ungroup { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-sticky-note-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-sticky-note-o { + --fa: "\f249"; } + +.fa.fa-cc-jcb { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-diners-club { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-clone { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hourglass-o { + --fa: "\f254"; } + +.fa.fa-hourglass-1 { + --fa: "\f251"; } + +.fa.fa-hourglass-2 { + --fa: "\f252"; } + +.fa.fa-hourglass-3 { + --fa: "\f253"; } + +.fa.fa-hand-rock-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-rock-o { + --fa: "\f255"; } + +.fa.fa-hand-grab-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-grab-o { + --fa: "\f255"; } + +.fa.fa-hand-paper-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-paper-o { + --fa: "\f256"; } + +.fa.fa-hand-stop-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-stop-o { + --fa: "\f256"; } + +.fa.fa-hand-scissors-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-scissors-o { + --fa: "\f257"; } + +.fa.fa-hand-lizard-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-lizard-o { + --fa: "\f258"; } + +.fa.fa-hand-spock-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-spock-o { + --fa: "\f259"; } + +.fa.fa-hand-pointer-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-pointer-o { + --fa: "\f25a"; } + +.fa.fa-hand-peace-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-peace-o { + --fa: "\f25b"; } + +.fa.fa-registered { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-creative-commons { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gg { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gg-circle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-odnoklassniki { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-odnoklassniki-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-odnoklassniki-square { + --fa: "\f264"; } + +.fa.fa-get-pocket { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wikipedia-w { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-safari { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-chrome { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-firefox { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-opera { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-internet-explorer { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-television { + --fa: "\f26c"; } + +.fa.fa-contao { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-500px { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-amazon { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-calendar-plus-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-calendar-plus-o { + --fa: "\f271"; } + +.fa.fa-calendar-minus-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-calendar-minus-o { + --fa: "\f272"; } + +.fa.fa-calendar-times-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-calendar-times-o { + --fa: "\f273"; } + +.fa.fa-calendar-check-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-calendar-check-o { + --fa: "\f274"; } + +.fa.fa-map-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-map-o { + --fa: "\f279"; } + +.fa.fa-commenting { + --fa: "\f4ad"; } + +.fa.fa-commenting-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-commenting-o { + --fa: "\f4ad"; } + +.fa.fa-houzz { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-vimeo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-vimeo { + --fa: "\f27d"; } + +.fa.fa-black-tie { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-fonticons { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-reddit-alien { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-edge { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-credit-card-alt { + --fa: "\f09d"; } + +.fa.fa-codiepie { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-modx { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-fort-awesome { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-usb { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-product-hunt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-mixcloud { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-scribd { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pause-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-pause-circle-o { + --fa: "\f28b"; } + +.fa.fa-stop-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-stop-circle-o { + --fa: "\f28d"; } + +.fa.fa-bluetooth { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bluetooth-b { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gitlab { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wpbeginner { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wpforms { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-envira { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wheelchair-alt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wheelchair-alt { + --fa: "\f368"; } + +.fa.fa-question-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-question-circle-o { + --fa: "\f059"; } + +.fa.fa-volume-control-phone { + --fa: "\f2a0"; } + +.fa.fa-asl-interpreting { + --fa: "\f2a3"; } + +.fa.fa-deafness { + --fa: "\f2a4"; } + +.fa.fa-hard-of-hearing { + --fa: "\f2a4"; } + +.fa.fa-glide { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-glide-g { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-signing { + --fa: "\f2a7"; } + +.fa.fa-viadeo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-viadeo-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-viadeo-square { + --fa: "\f2aa"; } + +.fa.fa-snapchat { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-snapchat-ghost { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-snapchat-ghost { + --fa: "\f2ab"; } + +.fa.fa-snapchat-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-snapchat-square { + --fa: "\f2ad"; } + +.fa.fa-pied-piper { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-first-order { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-yoast { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-themeisle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-plus-official { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-plus-official { + --fa: "\f2b3"; } + +.fa.fa-google-plus-circle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-plus-circle { + --fa: "\f2b3"; } + +.fa.fa-font-awesome { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-fa { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-fa { + --fa: "\f2b4"; } + +.fa.fa-handshake-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-handshake-o { + --fa: "\f2b5"; } + +.fa.fa-envelope-open-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-envelope-open-o { + --fa: "\f2b6"; } + +.fa.fa-linode { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-address-book-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-address-book-o { + --fa: "\f2b9"; } + +.fa.fa-vcard { + --fa: "\f2bb"; } + +.fa.fa-address-card-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-address-card-o { + --fa: "\f2bb"; } + +.fa.fa-vcard-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-vcard-o { + --fa: "\f2bb"; } + +.fa.fa-user-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-user-circle-o { + --fa: "\f2bd"; } + +.fa.fa-user-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-user-o { + --fa: "\f007"; } + +.fa.fa-id-badge { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-drivers-license { + --fa: "\f2c2"; } + +.fa.fa-id-card-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-id-card-o { + --fa: "\f2c2"; } + +.fa.fa-drivers-license-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-drivers-license-o { + --fa: "\f2c2"; } + +.fa.fa-quora { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-free-code-camp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-telegram { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-thermometer-4 { + --fa: "\f2c7"; } + +.fa.fa-thermometer { + --fa: "\f2c7"; } + +.fa.fa-thermometer-3 { + --fa: "\f2c8"; } + +.fa.fa-thermometer-2 { + --fa: "\f2c9"; } + +.fa.fa-thermometer-1 { + --fa: "\f2ca"; } + +.fa.fa-thermometer-0 { + --fa: "\f2cb"; } + +.fa.fa-bathtub { + --fa: "\f2cd"; } + +.fa.fa-s15 { + --fa: "\f2cd"; } + +.fa.fa-window-maximize { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-window-restore { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-times-rectangle { + --fa: "\f410"; } + +.fa.fa-window-close-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-window-close-o { + --fa: "\f410"; } + +.fa.fa-times-rectangle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-times-rectangle-o { + --fa: "\f410"; } + +.fa.fa-bandcamp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-grav { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-etsy { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-imdb { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-ravelry { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-eercast { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-eercast { + --fa: "\f2da"; } + +.fa.fa-snowflake-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-snowflake-o { + --fa: "\f2dc"; } + +.fa.fa-superpowers { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wpexplorer { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-meetup { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +*, +*: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; } } +iframe[src*=disqus] { + color-scheme: light; } + +a { + font-weight: 500; + color: #1565c0; + text-decoration: none; + transition: all 0.25s ease-in; } + a:focus, a:hover { + text-decoration: underline; } + +p { + margin: 2rem 0 2rem 0; + white-space: pre-wrap; + white-space: -moz-pre-wrap; + white-space: -pre-wrap; + white-space: -o-pre-wrap; + word-wrap: break-word; } + @media only screen and (max-width: 768px) { + p { + margin: 1.5rem 0 1.5rem 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 0; } + 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: 2rem 0 2rem; + padding: 1rem; + border-radius: 1rem; + overflow-x: auto; } + +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: 2rem 0 2rem; + padding: 1rem; + border-radius: 1rem; } + 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; + border-radius: 0.6rem; + padding: 0.3rem 0.6rem; + background-color: #ccc; + color: #212121; } + @media only screen and (max-width: 768px) { + code { + font-size: 1.5rem; } } +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; } + +.footnotes ol li p { + margin: 0; } + +.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; } + +.content { + flex: 1; + display: flex; + margin-top: 1.6rem; + margin-bottom: 3.2rem; } + @media only screen and (max-width: 768px) { + .content { + margin-top: 1rem; + margin-bottom: 1.6rem; } } + .content header { + margin-top: 6.4rem; + margin-bottom: 3.2rem; } + .content header h1 { + font-size: 4.2rem; + line-height: 4.6rem; + margin: 0; } + @media only screen and (max-width: 768px) { + .content header h1 { + font-size: 4rem; + line-height: 4.4rem; } } + .content article a:where(.external-link):not(:has(img)):after { + content: "\f08e"; + padding-left: 0.5em; + font-size: 0.75em; } + .content article details summary { + cursor: pointer; } + .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; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; } + .content .post .post-title { + margin-bottom: 0.75em; } + .content .post .post-meta i { + text-align: center; + width: 1.6rem; + margin-left: 0; + margin-right: 0.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: 0.3rem 0.6rem; + background-color: #e0e0e0; + border-radius: 0.6rem; + line-height: 1.5em; } + .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: 17rem; } } +.list ul { + margin: 3.2rem 0 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 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: 0.5rem; } + .centered .about h2 { + margin-top: 1rem; + margin-bottom: 0.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 0; + padding: 0; + cursor: pointer; } + .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.5rem; } } + .centered .error { + text-align: center; } + .centered .error h1 { + margin-top: 2rem; + margin-bottom: 0.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: 0.2rem; + position: relative; + margin: 2rem 0; + padding: 0 0.75rem; + overflow: auto; } + .notice .notice-title { + position: relative; + font-weight: 700; + margin: 0 -0.75rem; + padding: 0.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 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: 0.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 0.25s, max-height 0.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 { + display: initial; + position: relative; + visibility: hidden; } + .navigation #menu-toggle:checked + label > i { + color: #e0e0e0; } + .navigation #menu-toggle:checked + label + ul { + visibility: visible; + opacity: 1; + max-height: 100rem; } + .navigation #menu-toggle:focus-visible + label { + outline-style: auto; } } + .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 { + display: flex; + justify-content: center; + 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; + padding: 0 5px 0 5px; + margin: 0; + text-align: center; + width: 2.2rem; } + .pagination li a { + font-weight: 300; } + +.tabs { + display: flex; + flex-wrap: wrap; + margin: 2rem 0 2rem 0; + position: relative; } + .tabs.tabs-left { + justify-content: flex-start; } + .tabs.tabs-left label.tab-label { + margin-right: 0.5rem; } + .tabs.tabs-left .tab-content { + border-radius: 0px 4px 4px 4px; } + .tabs.tabs-right { + justify-content: flex-end; } + .tabs.tabs-right label.tab-label { + margin-left: 0.5rem; } + .tabs.tabs-right .tab-content { + border-radius: 4px 0px 4px 4px; } + .tabs input.tab-input { + display: none; } + .tabs label.tab-label { + background-color: #e0e0e0; + border-color: #ccc; + border-radius: 4px 4px 0px 0px; + border-style: solid; + border-bottom-style: hidden; + border-width: 1px; + cursor: pointer; + display: inline-block; + order: 1; + padding: 0.3rem 0.6rem; + position: relative; + top: 1px; + user-select: none; } + .tabs input.tab-input:checked + label.tab-label { + background-color: #fafafa; } + .tabs .tab-content { + background-color: #fafafa; + border-color: #ccc; + border-style: solid; + border-width: 1px; + display: none; + order: 2; + padding: 1rem; + width: 100%; } + .tabs.tabs-code .tab-content { + padding: 0.5rem; } + .tabs.tabs-code .tab-content pre { + margin: 0; } + +.taxonomy li { + display: inline-block; + margin: 0.9rem; } + +.taxonomy .taxonomy-element { + display: block; + padding: 0.3rem 0.9rem; + background-color: #e0e0e0; + border-radius: 0.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; } + @media only screen and (max-width: 768px) { + .footer { + font-size: 1.5rem; } } + .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: 0.2rem; + opacity: 0.5; + transition: all 0.25s ease-in; } + .float-container a:hover, .float-container a:focus { + color: #1565c0; + opacity: 1; } + @media only screen and (max-width: 768px) { + .float-container a:hover, .float-container a:focus { + color: #000; + opacity: 0.5; } } + .float-container a i { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); } + +.mastodon-wrapper { + display: flex; + gap: 3rem; + flex-direction: row; } + +.comment-level { + max-width: 3rem; + min-width: 3rem; } + +.reply-original { + display: none; } + +.mastodon-comment { + background-color: var(--body-background); + border-radius: var(--card-border-radius); + padding: var(--card-padding); + margin-bottom: 1rem; + display: flex; + gap: 1rem; + flex-direction: column; + flex-grow: 2; } + .mastodon-comment .comment { + display: flex; + flex-direction: row; + gap: 1rem; + flex-wrap: true; } + .mastodon-comment .comment-avatar img { + width: 6rem; } + .mastodon-comment .content { + flex-grow: 2; } + .mastodon-comment .comment-author { + display: flex; + flex-direction: column; } + .mastodon-comment .comment-author-name { + font-weight: bold; } + .mastodon-comment .comment-author-name a { + display: flex; + align-items: center; } + .mastodon-comment .comment-author-date { + margin-left: auto; } + .mastodon-comment .disabled { + color: var(--accent-color); } + +.mastodon-comment-content p:first-child { + margin-top: 0; } + +.mastodon { + --dlg-bg: #282c37; + --dlg-w: 600px; + --dlg-color: #9baec8; + --dlg-button-p: 0.75em 2em; + --dlg-outline-c: #00D9F5; } + +/* Background */ +.bg { + background-color: #ffffff; } + +/* PreWrapper */ +.chroma { + background-color: #ffffff; } + +/* Other */ +/* Error */ +.chroma .err { + color: #a61717; + background-color: #e3d2d2; } + +/* CodeLine */ +/* LineLink */ +.chroma .lnlinks { + outline: none; + text-decoration: none; + color: inherit; } + +/* LineTableTD */ +.chroma .lntd { + vertical-align: top; + padding: 0; + margin: 0; + border: 0; } + +/* LineTable */ +.chroma .lntable { + border-spacing: 0; + padding: 0; + margin: 0; + border: 0; } + +/* LineHighlight */ +.chroma .hl { + background-color: #ffffcc; } + +/* LineNumbersTable */ +.chroma .lnt { + white-space: pre; + user-select: none; + margin-right: 0.4em; + padding: 0 0.4em 0 0.4em; + color: #7f7f7f; } + +/* LineNumbers */ +.chroma .ln { + white-space: pre; + user-select: none; + margin-right: 0.4em; + padding: 0 0.4em 0 0.4em; + color: #7f7f7f; } + +/* Line */ +.chroma .line { + display: flex; } + +/* Keyword */ +.chroma .k { + color: #000000; + font-weight: bold; } + +/* KeywordConstant */ +.chroma .kc { + color: #000000; + font-weight: bold; } + +/* KeywordDeclaration */ +.chroma .kd { + color: #000000; + font-weight: bold; } + +/* KeywordNamespace */ +.chroma .kn { + color: #000000; + font-weight: bold; } + +/* KeywordPseudo */ +.chroma .kp { + color: #000000; + font-weight: bold; } + +/* KeywordReserved */ +.chroma .kr { + color: #000000; + font-weight: bold; } + +/* KeywordType */ +.chroma .kt { + color: #445588; + font-weight: bold; } + +/* Name */ +/* NameAttribute */ +.chroma .na { + color: #008080; } + +/* NameBuiltin */ +.chroma .nb { + color: #0086b3; } + +/* NameBuiltinPseudo */ +.chroma .bp { + color: #999999; } + +/* NameClass */ +.chroma .nc { + color: #445588; + font-weight: bold; } + +/* NameConstant */ +.chroma .no { + color: #008080; } + +/* NameDecorator */ +.chroma .nd { + color: #3c5d5d; + font-weight: bold; } + +/* NameEntity */ +.chroma .ni { + color: #800080; } + +/* NameException */ +.chroma .ne { + color: #990000; + font-weight: bold; } + +/* NameFunction */ +.chroma .nf { + color: #990000; + font-weight: bold; } + +/* NameFunctionMagic */ +/* NameLabel */ +.chroma .nl { + color: #990000; + font-weight: bold; } + +/* NameNamespace */ +.chroma .nn { + color: #555555; } + +/* NameOther */ +/* NameProperty */ +/* NameTag */ +.chroma .nt { + color: #000080; } + +/* NameVariable */ +.chroma .nv { + color: #008080; } + +/* NameVariableClass */ +.chroma .vc { + color: #008080; } + +/* NameVariableGlobal */ +.chroma .vg { + color: #008080; } + +/* NameVariableInstance */ +.chroma .vi { + color: #008080; } + +/* NameVariableMagic */ +/* Literal */ +/* LiteralDate */ +/* LiteralString */ +.chroma .s { + color: #dd1144; } + +/* LiteralStringAffix */ +.chroma .sa { + color: #dd1144; } + +/* LiteralStringBacktick */ +.chroma .sb { + color: #dd1144; } + +/* LiteralStringChar */ +.chroma .sc { + color: #dd1144; } + +/* LiteralStringDelimiter */ +.chroma .dl { + color: #dd1144; } + +/* LiteralStringDoc */ +.chroma .sd { + color: #dd1144; } + +/* LiteralStringDouble */ +.chroma .s2 { + color: #dd1144; } + +/* LiteralStringEscape */ +.chroma .se { + color: #dd1144; } + +/* LiteralStringHeredoc */ +.chroma .sh { + color: #dd1144; } + +/* LiteralStringInterpol */ +.chroma .si { + color: #dd1144; } + +/* LiteralStringOther */ +.chroma .sx { + color: #dd1144; } + +/* LiteralStringRegex */ +.chroma .sr { + color: #009926; } + +/* LiteralStringSingle */ +.chroma .s1 { + color: #dd1144; } + +/* LiteralStringSymbol */ +.chroma .ss { + color: #990073; } + +/* LiteralNumber */ +.chroma .m { + color: #009999; } + +/* LiteralNumberBin */ +.chroma .mb { + color: #009999; } + +/* LiteralNumberFloat */ +.chroma .mf { + color: #009999; } + +/* LiteralNumberHex */ +.chroma .mh { + color: #009999; } + +/* LiteralNumberInteger */ +.chroma .mi { + color: #009999; } + +/* LiteralNumberIntegerLong */ +.chroma .il { + color: #009999; } + +/* LiteralNumberOct */ +.chroma .mo { + color: #009999; } + +/* Operator */ +.chroma .o { + color: #000000; + font-weight: bold; } + +/* OperatorWord */ +.chroma .ow { + color: #000000; + font-weight: bold; } + +/* Punctuation */ +/* Comment */ +.chroma .c { + color: #999988; + font-style: italic; } + +/* CommentHashbang */ +.chroma .ch { + color: #999988; + font-style: italic; } + +/* CommentMultiline */ +.chroma .cm { + color: #999988; + font-style: italic; } + +/* CommentSingle */ +.chroma .c1 { + color: #999988; + font-style: italic; } + +/* CommentSpecial */ +.chroma .cs { + color: #999999; + font-weight: bold; + font-style: italic; } + +/* CommentPreproc */ +.chroma .cp { + color: #999999; + font-weight: bold; + font-style: italic; } + +/* CommentPreprocFile */ +.chroma .cpf { + color: #999999; + font-weight: bold; + font-style: italic; } + +/* Generic */ +/* GenericDeleted */ +.chroma .gd { + color: #000000; + background-color: #ffdddd; } + +/* GenericEmph */ +.chroma .ge { + color: #000000; + font-style: italic; } + +/* GenericError */ +.chroma .gr { + color: #aa0000; } + +/* GenericHeading */ +.chroma .gh { + color: #999999; } + +/* GenericInserted */ +.chroma .gi { + color: #000000; + background-color: #ddffdd; } + +/* GenericOutput */ +.chroma .go { + color: #888888; } + +/* GenericPrompt */ +.chroma .gp { + color: #555555; } + +/* GenericStrong */ +.chroma .gs { + font-weight: bold; } + +/* GenericSubheading */ +.chroma .gu { + color: #aaaaaa; } + +/* GenericTraceback */ +.chroma .gt { + color: #aa0000; } + +/* GenericUnderline */ +.chroma .gl { + text-decoration: underline; } + +/* TextWhitespace */ +.chroma .w { + color: #bbbbbb; } + +/*# sourceMappingURL=coder.css.map */ \ No newline at end of file diff --git a/public/css/coder.css.map b/public/css/coder.css.map new file mode 100644 index 00000000..3f3017c6 --- /dev/null +++ b/public/css/coder.css.map @@ -0,0 +1,93 @@ +{ + "version": 3, + "file": "coder.css", + "sourceRoot": "/Users/Ryan.Nemeth/repos/rnemeth90.github.io", + "sources": [ + "themes/hugo-coder/assets/scss/coder.scss", + "themes/hugo-coder/assets/scss/css/normalize.css", + "themes/hugo-coder/assets/scss/_variables.scss", + "themes/hugo-coder/assets/scss/font-awesome/fontawesome.scss", + "themes/hugo-coder/assets/scss/font-awesome/_functions.scss", + "themes/hugo-coder/assets/scss/font-awesome/_variables.scss", + "themes/hugo-coder/assets/scss/font-awesome/_mixins.scss", + "themes/hugo-coder/assets/scss/font-awesome/_core.scss", + "themes/hugo-coder/assets/scss/font-awesome/_sizing.scss", + "themes/hugo-coder/assets/scss/font-awesome/_fixed-width.scss", + "themes/hugo-coder/assets/scss/font-awesome/_list.scss", + "themes/hugo-coder/assets/scss/font-awesome/_bordered-pulled.scss", + "themes/hugo-coder/assets/scss/font-awesome/_animated.scss", + "themes/hugo-coder/assets/scss/font-awesome/_rotated-flipped.scss", + "themes/hugo-coder/assets/scss/font-awesome/_stacked.scss", + "themes/hugo-coder/assets/scss/font-awesome/_icons.scss", + "themes/hugo-coder/assets/scss/font-awesome/_screen-reader.scss", + "themes/hugo-coder/assets/scss/font-awesome/regular.scss", + "themes/hugo-coder/assets/scss/font-awesome/_functions.scss", + "themes/hugo-coder/assets/scss/font-awesome/_variables.scss", + "themes/hugo-coder/assets/scss/font-awesome/solid.scss", + "themes/hugo-coder/assets/scss/font-awesome/_functions.scss", + "themes/hugo-coder/assets/scss/font-awesome/_variables.scss", + "themes/hugo-coder/assets/scss/font-awesome/brands.scss", + "themes/hugo-coder/assets/scss/font-awesome/_functions.scss", + "themes/hugo-coder/assets/scss/font-awesome/_variables.scss", + "themes/hugo-coder/assets/scss/font-awesome/v4-shims.scss", + "themes/hugo-coder/assets/scss/font-awesome/_functions.scss", + "themes/hugo-coder/assets/scss/font-awesome/_variables.scss", + "themes/hugo-coder/assets/scss/font-awesome/_shims.scss", + "themes/hugo-coder/assets/scss/_base.scss", + "themes/hugo-coder/assets/scss/_content.scss", + "themes/hugo-coder/assets/scss/_notices.scss", + "themes/hugo-coder/assets/scss/_navigation.scss", + "themes/hugo-coder/assets/scss/_pagination.scss", + "themes/hugo-coder/assets/scss/_tabs.scss", + "themes/hugo-coder/assets/scss/_taxonomies.scss", + "themes/hugo-coder/assets/scss/_footer.scss", + "themes/hugo-coder/assets/scss/_float.scss", + "themes/hugo-coder/assets/scss/_mastodon.scss", + "themes/hugo-coder/assets/scss/_syntax.scss" + ], + "sourcesContent": [ + "@import \"css/normalize\";\n@import \"variables\";\n@import \"font-awesome/fontawesome\";\n@import \"font-awesome/regular\";\n@import \"font-awesome/solid\";\n@import \"font-awesome/brands\";\n@import \"font-awesome/v4-shims\";\n@import \"base\";\n@import \"content\";\n@import \"notices\";\n@import \"navigation\";\n@import \"pagination\";\n@import \"tabs\";\n@import \"taxonomies\";\n@import \"footer\";\n@import \"float\";\n@import \"mastodon\";\n@import \"syntax\";", + "/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */\n\n/* Document\n ========================================================================== */\n\n/**\n * 1. Correct the line height in all browsers.\n * 2. Prevent adjustments of font size after orientation changes in iOS.\n */\n\n html {\n line-height: 1.15; /* 1 */\n -webkit-text-size-adjust: 100%; /* 2 */\n }\n \n /* Sections\n ========================================================================== */\n \n /**\n * Remove the margin in all browsers.\n */\n \n body {\n margin: 0;\n }\n \n /**\n * Render the `main` element consistently in IE.\n */\n \n main {\n display: block;\n }\n \n /**\n * Correct the font size and margin on `h1` elements within `section` and\n * `article` contexts in Chrome, Firefox, and Safari.\n */\n \n h1 {\n font-size: 2em;\n margin: 0.67em 0;\n }\n \n /* Grouping content\n ========================================================================== */\n \n /**\n * 1. Add the correct box sizing in Firefox.\n * 2. Show the overflow in Edge and IE.\n */\n \n hr {\n box-sizing: content-box; /* 1 */\n height: 0; /* 1 */\n overflow: visible; /* 2 */\n }\n \n /**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd `em` font sizing in all browsers.\n */\n \n pre {\n font-family: monospace, monospace; /* 1 */\n font-size: 1em; /* 2 */\n }\n \n /* Text-level semantics\n ========================================================================== */\n \n /**\n * Remove the gray background on active links in IE 10.\n */\n \n a {\n background-color: transparent;\n word-wrap: break-word;\n }\n \n /**\n * 1. Remove the bottom border in Chrome 57-\n * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.\n */\n \n abbr[title] {\n border-bottom: none; /* 1 */\n text-decoration: underline; /* 2 */\n text-decoration: underline dotted; /* 2 */\n }\n \n /**\n * Add the correct font weight in Chrome, Edge, and Safari.\n */\n \n b,\n strong {\n font-weight: bolder;\n }\n \n /**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd `em` font sizing in all browsers.\n */\n \n code,\n kbd,\n samp {\n font-family: monospace, monospace; /* 1 */\n font-size: 1em; /* 2 */\n }\n \n /**\n * Add the correct font size in all browsers.\n */\n \n small {\n font-size: 80%;\n }\n \n /**\n * Prevent `sub` and `sup` elements from affecting the line height in\n * all browsers.\n */\n \n sub,\n sup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n }\n \n sub {\n bottom: -0.25em;\n }\n \n sup {\n top: -0.5em;\n }\n \n /* Embedded content\n ========================================================================== */\n \n /**\n * Remove the border on images inside links in IE 10.\n */\n \n img {\n border-style: none;\n }\n \n /* Forms\n ========================================================================== */\n \n /**\n * 1. Change the font styles in all browsers.\n * 2. Remove the margin in Firefox and Safari.\n */\n \n button,\n input,\n optgroup,\n select,\n textarea {\n font-family: inherit; /* 1 */\n font-size: 100%; /* 1 */\n line-height: 1.15; /* 1 */\n margin: 0; /* 2 */\n }\n \n /**\n * Show the overflow in IE.\n * 1. Show the overflow in Edge.\n */\n \n button,\n input { /* 1 */\n overflow: visible;\n }\n \n /**\n * Remove the inheritance of text transform in Edge, Firefox, and IE.\n * 1. Remove the inheritance of text transform in Firefox.\n */\n \n button,\n select { /* 1 */\n text-transform: none;\n }\n \n /**\n * Correct the inability to style clickable types in iOS and Safari.\n */\n \n button,\n [type=\"button\"],\n [type=\"reset\"],\n [type=\"submit\"] {\n -webkit-appearance: button;\n }\n \n /**\n * Remove the inner border and padding in Firefox.\n */\n \n button::-moz-focus-inner,\n [type=\"button\"]::-moz-focus-inner,\n [type=\"reset\"]::-moz-focus-inner,\n [type=\"submit\"]::-moz-focus-inner {\n border-style: none;\n padding: 0;\n }\n \n /**\n * Restore the focus styles unset by the previous rule.\n */\n \n button:-moz-focusring,\n [type=\"button\"]:-moz-focusring,\n [type=\"reset\"]:-moz-focusring,\n [type=\"submit\"]:-moz-focusring {\n outline: 1px dotted ButtonText;\n }\n \n /**\n * Correct the padding in Firefox.\n */\n \n fieldset {\n padding: 0.35em 0.75em 0.625em;\n }\n \n /**\n * 1. Correct the text wrapping in Edge and IE.\n * 2. Correct the color inheritance from `fieldset` elements in IE.\n * 3. Remove the padding so developers are not caught out when they zero out\n * `fieldset` elements in all browsers.\n */\n \n legend {\n box-sizing: border-box; /* 1 */\n color: inherit; /* 2 */\n display: table; /* 1 */\n max-width: 100%; /* 1 */\n padding: 0; /* 3 */\n white-space: normal; /* 1 */\n }\n \n /**\n * Add the correct vertical alignment in Chrome, Firefox, and Opera.\n */\n \n progress {\n vertical-align: baseline;\n }\n \n /**\n * Remove the default vertical scrollbar in IE 10+.\n */\n \n textarea {\n overflow: auto;\n }\n \n /**\n * 1. Add the correct box sizing in IE 10.\n * 2. Remove the padding in IE 10.\n */\n \n [type=\"checkbox\"],\n [type=\"radio\"] {\n box-sizing: border-box; /* 1 */\n padding: 0; /* 2 */\n }\n \n /**\n * Correct the cursor style of increment and decrement buttons in Chrome.\n */\n \n [type=\"number\"]::-webkit-inner-spin-button,\n [type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n }\n \n /**\n * 1. Correct the odd appearance in Chrome and Safari.\n * 2. Correct the outline style in Safari.\n */\n \n [type=\"search\"] {\n -webkit-appearance: textfield; /* 1 */\n outline-offset: -2px; /* 2 */\n }\n \n /**\n * Remove the inner padding in Chrome and Safari on macOS.\n */\n \n [type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n }\n \n /**\n * 1. Correct the inability to style clickable types in iOS and Safari.\n * 2. Change font properties to `inherit` in Safari.\n */\n \n ::-webkit-file-upload-button {\n -webkit-appearance: button; /* 1 */\n font: inherit; /* 2 */\n }\n \n /* Interactive\n ========================================================================== */\n \n /*\n * Add the correct display in Edge, IE 10+, and Firefox.\n */\n \n details {\n display: block;\n }\n \n /*\n * Add the correct display in all browsers.\n */\n \n summary {\n display: list-item;\n }\n \n /* Misc\n ========================================================================== */\n \n /**\n * Add the correct display in IE 10+.\n */\n \n template {\n display: none;\n }\n \n /**\n * Add the correct display in IE 10.\n */\n \n [hidden] {\n display: none;\n }\n", + "// Fonts\n$font-family: -apple-system,\nBlinkMacSystemFont,\n\"Segoe UI\",\nRoboto,\nOxygen-Sans,\nUbuntu,\nCantarell,\n\"Helvetica Neue\",\nHelvetica,\n\"游ゴシック\",\n\"PingFang SC\",\nSTXihei,\"华文细黑\",\n\"Microsoft YaHei\",\"微软雅黑\",\nSimSun,\"宋体\",\nHeiti,\"黑体\",\nsans-serif;\n$code-font-family: SFMono-Regular,\nConsolas,\nLiberation Mono,\nMenlo,\nmonospace;\n\n// Colors\n$bg-color: #fafafa !default;\n$fg-color: #212121 !default;\n$alt-bg-color: #e0e0e0 !default;\n$alt-fg-color: #000 !default;\n$darker-alt-bg-color: #ccc !default;\n$link-color: #1565c0 !default;\n\n// Dark colors\n$bg-color-dark: #212121 !default;\n$fg-color-dark: #dadada !default;\n$alt-bg-color-dark: #424242 !default;\n$alt-fg-color-dark: #dadada !default;\n$lighter-alt-bg-color-dark: #4f4f4f !default;\n$link-color-dark: #42a5f5 !default;\n\n// Notice colors\n$fg-color-notice-note-icon: #5e35b1 !default;\n$bg-color-notice-note-title: #673ab71a !default;\n$bg-color-notice-note-content: #7e57c21a !default;\n$fg-color-notice-tip-icon: #00897b !default;\n$bg-color-notice-tip-title: #0096881a !default;\n$bg-color-notice-tip-content: #26a69a1a !default;\n$fg-color-notice-example-icon: #6d4c41 !default;\n$bg-color-notice-example-title: #7955481a !default;\n$bg-color-notice-example-content: #8d6e631a !default;\n$fg-color-notice-question-icon: #7cb342 !default;\n$bg-color-notice-question-title: #8bc34a1a !default;\n$bg-color-notice-question-content: #9ccc651a !default;\n$fg-color-notice-info-icon: #1e88e5 !default;\n$bg-color-notice-info-title: #2196f31a !default;\n$bg-color-notice-info-content: #42a5f51a !default;\n$fg-color-notice-warning-icon: #ffb300 !default;\n$bg-color-notice-warning-title: #ffc1071a !default;\n$bg-color-notice-warning-content: #ffca281a !default;\n$fg-color-notice-error-icon: #e53935 !default;\n$bg-color-notice-error-title: #f443361a !default;\n$bg-color-notice-error-content: #ef53501a !default;\n\n// Path to FontAwesome TTF/WOFF files.\n$fa-font-path: \"../fonts\" !default;\n", + "/*!\n * Font Awesome Free 6.7.1 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n * Copyright 2024 Fonticons, Inc.\n */\n// Font Awesome core compile (Web Fonts-based)\n// -------------------------\n\n@import 'functions';\n@import 'variables';\n@import 'mixins';\n@import 'core';\n@import 'sizing';\n@import 'fixed-width';\n@import 'list';\n@import 'bordered-pulled';\n@import 'animated';\n@import 'rotated-flipped';\n@import 'stacked';\n@import 'icons';\n@import 'screen-reader';\n", + "// functions\n// --------------------------\n\n// fa-content: convenience function used to set content property\n@function fa-content($fa-var) {\n @return unquote(\"\\\"#{ $fa-var }\\\"\");\n}\n\n// fa-divide: Originally obtained from the Bootstrap https://github.com/twbs/bootstrap\n//\n// Licensed under: The MIT License (MIT)\n//\n// Copyright (c) 2011-2021 Twitter, Inc.\n// Copyright (c) 2011-2021 The Bootstrap Authors\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n@function fa-divide($dividend, $divisor, $precision: 10) {\n $sign: if($dividend > 0 and $divisor > 0, 1, -1);\n $dividend: abs($dividend);\n $divisor: abs($divisor);\n $quotient: 0;\n $remainder: $dividend;\n @if $dividend == 0 {\n @return 0;\n }\n @if $divisor == 0 {\n @error \"Cannot divide by 0\";\n }\n @if $divisor == 1 {\n @return $dividend;\n }\n @while $remainder >= $divisor {\n $quotient: $quotient + 1;\n $remainder: $remainder - $divisor;\n }\n @if $remainder > 0 and $precision > 0 {\n $remainder: fa-divide($remainder * 10, $divisor, $precision - 1) * .1;\n }\n @return ($quotient + $remainder) * $sign;\n}\n", + "// variables\n// --------------------------\n\n$fa-css-prefix : fa !default;\n$fa-style : 900 !default;\n$fa-style-family : \"Font Awesome 6 Free\" !default;\n\n$fa-icon-property : --fa;\n$fa-duotone-icon-property : --fa--fa;\n\n$fa-display : inline-block !default;\n\n$fa-fw-width : fa-divide(20em, 16) !default;\n$fa-inverse : #fff !default;\n\n$fa-border-color : #eee !default;\n$fa-border-padding : .2em .25em .15em !default;\n$fa-border-radius : .1em !default;\n$fa-border-style : solid !default;\n$fa-border-width : .08em !default;\n\n$fa-size-scale-2xs : 10 !default;\n$fa-size-scale-xs : 12 !default;\n$fa-size-scale-sm : 14 !default;\n$fa-size-scale-base : 16 !default;\n$fa-size-scale-lg : 20 !default;\n$fa-size-scale-xl : 24 !default;\n$fa-size-scale-2xl : 32 !default;\n\n$fa-sizes: (\n \"2xs\" : $fa-size-scale-2xs,\n \"xs\" : $fa-size-scale-xs,\n \"sm\" : $fa-size-scale-sm,\n \"lg\" : $fa-size-scale-lg,\n \"xl\" : $fa-size-scale-xl,\n \"2xl\" : $fa-size-scale-2xl\n) !default;\n\n$fa-li-width : 2em !default;\n$fa-li-margin : $fa-li-width * fa-divide(5, 4) !default;\n\n$fa-pull-margin : .3em !default;\n\n$fa-primary-opacity : 1 !default;\n$fa-secondary-opacity : .4 !default;\n\n$fa-stack-vertical-align : middle !default;\n$fa-stack-width : ($fa-fw-width * 2) !default;\n$fa-stack-z-index : auto !default;\n\n$fa-font-display : block !default;\n$fa-font-path : \"../webfonts\" !default;\n\n$fa-var-0: \\30;\n$fa-var-1: \\31;\n$fa-var-2: \\32;\n$fa-var-3: \\33;\n$fa-var-4: \\34;\n$fa-var-5: \\35;\n$fa-var-6: \\36;\n$fa-var-7: \\37;\n$fa-var-8: \\38;\n$fa-var-9: \\39;\n$fa-var-fill-drip: \\f576;\n$fa-var-arrows-to-circle: \\e4bd;\n$fa-var-circle-chevron-right: \\f138;\n$fa-var-chevron-circle-right: \\f138;\n$fa-var-at: \\40;\n$fa-var-trash-can: \\f2ed;\n$fa-var-trash-alt: \\f2ed;\n$fa-var-text-height: \\f034;\n$fa-var-user-xmark: \\f235;\n$fa-var-user-times: \\f235;\n$fa-var-stethoscope: \\f0f1;\n$fa-var-message: \\f27a;\n$fa-var-comment-alt: \\f27a;\n$fa-var-info: \\f129;\n$fa-var-down-left-and-up-right-to-center: \\f422;\n$fa-var-compress-alt: \\f422;\n$fa-var-explosion: \\e4e9;\n$fa-var-file-lines: \\f15c;\n$fa-var-file-alt: \\f15c;\n$fa-var-file-text: \\f15c;\n$fa-var-wave-square: \\f83e;\n$fa-var-ring: \\f70b;\n$fa-var-building-un: \\e4d9;\n$fa-var-dice-three: \\f527;\n$fa-var-calendar-days: \\f073;\n$fa-var-calendar-alt: \\f073;\n$fa-var-anchor-circle-check: \\e4aa;\n$fa-var-building-circle-arrow-right: \\e4d1;\n$fa-var-volleyball: \\f45f;\n$fa-var-volleyball-ball: \\f45f;\n$fa-var-arrows-up-to-line: \\e4c2;\n$fa-var-sort-down: \\f0dd;\n$fa-var-sort-desc: \\f0dd;\n$fa-var-circle-minus: \\f056;\n$fa-var-minus-circle: \\f056;\n$fa-var-door-open: \\f52b;\n$fa-var-right-from-bracket: \\f2f5;\n$fa-var-sign-out-alt: \\f2f5;\n$fa-var-atom: \\f5d2;\n$fa-var-soap: \\e06e;\n$fa-var-icons: \\f86d;\n$fa-var-heart-music-camera-bolt: \\f86d;\n$fa-var-microphone-lines-slash: \\f539;\n$fa-var-microphone-alt-slash: \\f539;\n$fa-var-bridge-circle-check: \\e4c9;\n$fa-var-pump-medical: \\e06a;\n$fa-var-fingerprint: \\f577;\n$fa-var-hand-point-right: \\f0a4;\n$fa-var-magnifying-glass-location: \\f689;\n$fa-var-search-location: \\f689;\n$fa-var-forward-step: \\f051;\n$fa-var-step-forward: \\f051;\n$fa-var-face-smile-beam: \\f5b8;\n$fa-var-smile-beam: \\f5b8;\n$fa-var-flag-checkered: \\f11e;\n$fa-var-football: \\f44e;\n$fa-var-football-ball: \\f44e;\n$fa-var-school-circle-exclamation: \\e56c;\n$fa-var-crop: \\f125;\n$fa-var-angles-down: \\f103;\n$fa-var-angle-double-down: \\f103;\n$fa-var-users-rectangle: \\e594;\n$fa-var-people-roof: \\e537;\n$fa-var-people-line: \\e534;\n$fa-var-beer-mug-empty: \\f0fc;\n$fa-var-beer: \\f0fc;\n$fa-var-diagram-predecessor: \\e477;\n$fa-var-arrow-up-long: \\f176;\n$fa-var-long-arrow-up: \\f176;\n$fa-var-fire-flame-simple: \\f46a;\n$fa-var-burn: \\f46a;\n$fa-var-person: \\f183;\n$fa-var-male: \\f183;\n$fa-var-laptop: \\f109;\n$fa-var-file-csv: \\f6dd;\n$fa-var-menorah: \\f676;\n$fa-var-truck-plane: \\e58f;\n$fa-var-record-vinyl: \\f8d9;\n$fa-var-face-grin-stars: \\f587;\n$fa-var-grin-stars: \\f587;\n$fa-var-bong: \\f55c;\n$fa-var-spaghetti-monster-flying: \\f67b;\n$fa-var-pastafarianism: \\f67b;\n$fa-var-arrow-down-up-across-line: \\e4af;\n$fa-var-spoon: \\f2e5;\n$fa-var-utensil-spoon: \\f2e5;\n$fa-var-jar-wheat: \\e517;\n$fa-var-envelopes-bulk: \\f674;\n$fa-var-mail-bulk: \\f674;\n$fa-var-file-circle-exclamation: \\e4eb;\n$fa-var-circle-h: \\f47e;\n$fa-var-hospital-symbol: \\f47e;\n$fa-var-pager: \\f815;\n$fa-var-address-book: \\f2b9;\n$fa-var-contact-book: \\f2b9;\n$fa-var-strikethrough: \\f0cc;\n$fa-var-k: \\4b;\n$fa-var-landmark-flag: \\e51c;\n$fa-var-pencil: \\f303;\n$fa-var-pencil-alt: \\f303;\n$fa-var-backward: \\f04a;\n$fa-var-caret-right: \\f0da;\n$fa-var-comments: \\f086;\n$fa-var-paste: \\f0ea;\n$fa-var-file-clipboard: \\f0ea;\n$fa-var-code-pull-request: \\e13c;\n$fa-var-clipboard-list: \\f46d;\n$fa-var-truck-ramp-box: \\f4de;\n$fa-var-truck-loading: \\f4de;\n$fa-var-user-check: \\f4fc;\n$fa-var-vial-virus: \\e597;\n$fa-var-sheet-plastic: \\e571;\n$fa-var-blog: \\f781;\n$fa-var-user-ninja: \\f504;\n$fa-var-person-arrow-up-from-line: \\e539;\n$fa-var-scroll-torah: \\f6a0;\n$fa-var-torah: \\f6a0;\n$fa-var-broom-ball: \\f458;\n$fa-var-quidditch: \\f458;\n$fa-var-quidditch-broom-ball: \\f458;\n$fa-var-toggle-off: \\f204;\n$fa-var-box-archive: \\f187;\n$fa-var-archive: \\f187;\n$fa-var-person-drowning: \\e545;\n$fa-var-arrow-down-9-1: \\f886;\n$fa-var-sort-numeric-desc: \\f886;\n$fa-var-sort-numeric-down-alt: \\f886;\n$fa-var-face-grin-tongue-squint: \\f58a;\n$fa-var-grin-tongue-squint: \\f58a;\n$fa-var-spray-can: \\f5bd;\n$fa-var-truck-monster: \\f63b;\n$fa-var-w: \\57;\n$fa-var-earth-africa: \\f57c;\n$fa-var-globe-africa: \\f57c;\n$fa-var-rainbow: \\f75b;\n$fa-var-circle-notch: \\f1ce;\n$fa-var-tablet-screen-button: \\f3fa;\n$fa-var-tablet-alt: \\f3fa;\n$fa-var-paw: \\f1b0;\n$fa-var-cloud: \\f0c2;\n$fa-var-trowel-bricks: \\e58a;\n$fa-var-face-flushed: \\f579;\n$fa-var-flushed: \\f579;\n$fa-var-hospital-user: \\f80d;\n$fa-var-tent-arrow-left-right: \\e57f;\n$fa-var-gavel: \\f0e3;\n$fa-var-legal: \\f0e3;\n$fa-var-binoculars: \\f1e5;\n$fa-var-microphone-slash: \\f131;\n$fa-var-box-tissue: \\e05b;\n$fa-var-motorcycle: \\f21c;\n$fa-var-bell-concierge: \\f562;\n$fa-var-concierge-bell: \\f562;\n$fa-var-pen-ruler: \\f5ae;\n$fa-var-pencil-ruler: \\f5ae;\n$fa-var-people-arrows: \\e068;\n$fa-var-people-arrows-left-right: \\e068;\n$fa-var-mars-and-venus-burst: \\e523;\n$fa-var-square-caret-right: \\f152;\n$fa-var-caret-square-right: \\f152;\n$fa-var-scissors: \\f0c4;\n$fa-var-cut: \\f0c4;\n$fa-var-sun-plant-wilt: \\e57a;\n$fa-var-toilets-portable: \\e584;\n$fa-var-hockey-puck: \\f453;\n$fa-var-table: \\f0ce;\n$fa-var-magnifying-glass-arrow-right: \\e521;\n$fa-var-tachograph-digital: \\f566;\n$fa-var-digital-tachograph: \\f566;\n$fa-var-users-slash: \\e073;\n$fa-var-clover: \\e139;\n$fa-var-reply: \\f3e5;\n$fa-var-mail-reply: \\f3e5;\n$fa-var-star-and-crescent: \\f699;\n$fa-var-house-fire: \\e50c;\n$fa-var-square-minus: \\f146;\n$fa-var-minus-square: \\f146;\n$fa-var-helicopter: \\f533;\n$fa-var-compass: \\f14e;\n$fa-var-square-caret-down: \\f150;\n$fa-var-caret-square-down: \\f150;\n$fa-var-file-circle-question: \\e4ef;\n$fa-var-laptop-code: \\f5fc;\n$fa-var-swatchbook: \\f5c3;\n$fa-var-prescription-bottle: \\f485;\n$fa-var-bars: \\f0c9;\n$fa-var-navicon: \\f0c9;\n$fa-var-people-group: \\e533;\n$fa-var-hourglass-end: \\f253;\n$fa-var-hourglass-3: \\f253;\n$fa-var-heart-crack: \\f7a9;\n$fa-var-heart-broken: \\f7a9;\n$fa-var-square-up-right: \\f360;\n$fa-var-external-link-square-alt: \\f360;\n$fa-var-face-kiss-beam: \\f597;\n$fa-var-kiss-beam: \\f597;\n$fa-var-film: \\f008;\n$fa-var-ruler-horizontal: \\f547;\n$fa-var-people-robbery: \\e536;\n$fa-var-lightbulb: \\f0eb;\n$fa-var-caret-left: \\f0d9;\n$fa-var-circle-exclamation: \\f06a;\n$fa-var-exclamation-circle: \\f06a;\n$fa-var-school-circle-xmark: \\e56d;\n$fa-var-arrow-right-from-bracket: \\f08b;\n$fa-var-sign-out: \\f08b;\n$fa-var-circle-chevron-down: \\f13a;\n$fa-var-chevron-circle-down: \\f13a;\n$fa-var-unlock-keyhole: \\f13e;\n$fa-var-unlock-alt: \\f13e;\n$fa-var-cloud-showers-heavy: \\f740;\n$fa-var-headphones-simple: \\f58f;\n$fa-var-headphones-alt: \\f58f;\n$fa-var-sitemap: \\f0e8;\n$fa-var-circle-dollar-to-slot: \\f4b9;\n$fa-var-donate: \\f4b9;\n$fa-var-memory: \\f538;\n$fa-var-road-spikes: \\e568;\n$fa-var-fire-burner: \\e4f1;\n$fa-var-flag: \\f024;\n$fa-var-hanukiah: \\f6e6;\n$fa-var-feather: \\f52d;\n$fa-var-volume-low: \\f027;\n$fa-var-volume-down: \\f027;\n$fa-var-comment-slash: \\f4b3;\n$fa-var-cloud-sun-rain: \\f743;\n$fa-var-compress: \\f066;\n$fa-var-wheat-awn: \\e2cd;\n$fa-var-wheat-alt: \\e2cd;\n$fa-var-ankh: \\f644;\n$fa-var-hands-holding-child: \\e4fa;\n$fa-var-asterisk: \\2a;\n$fa-var-square-check: \\f14a;\n$fa-var-check-square: \\f14a;\n$fa-var-peseta-sign: \\e221;\n$fa-var-heading: \\f1dc;\n$fa-var-header: \\f1dc;\n$fa-var-ghost: \\f6e2;\n$fa-var-list: \\f03a;\n$fa-var-list-squares: \\f03a;\n$fa-var-square-phone-flip: \\f87b;\n$fa-var-phone-square-alt: \\f87b;\n$fa-var-cart-plus: \\f217;\n$fa-var-gamepad: \\f11b;\n$fa-var-circle-dot: \\f192;\n$fa-var-dot-circle: \\f192;\n$fa-var-face-dizzy: \\f567;\n$fa-var-dizzy: \\f567;\n$fa-var-egg: \\f7fb;\n$fa-var-house-medical-circle-xmark: \\e513;\n$fa-var-campground: \\f6bb;\n$fa-var-folder-plus: \\f65e;\n$fa-var-futbol: \\f1e3;\n$fa-var-futbol-ball: \\f1e3;\n$fa-var-soccer-ball: \\f1e3;\n$fa-var-paintbrush: \\f1fc;\n$fa-var-paint-brush: \\f1fc;\n$fa-var-lock: \\f023;\n$fa-var-gas-pump: \\f52f;\n$fa-var-hot-tub-person: \\f593;\n$fa-var-hot-tub: \\f593;\n$fa-var-map-location: \\f59f;\n$fa-var-map-marked: \\f59f;\n$fa-var-house-flood-water: \\e50e;\n$fa-var-tree: \\f1bb;\n$fa-var-bridge-lock: \\e4cc;\n$fa-var-sack-dollar: \\f81d;\n$fa-var-pen-to-square: \\f044;\n$fa-var-edit: \\f044;\n$fa-var-car-side: \\f5e4;\n$fa-var-share-nodes: \\f1e0;\n$fa-var-share-alt: \\f1e0;\n$fa-var-heart-circle-minus: \\e4ff;\n$fa-var-hourglass-half: \\f252;\n$fa-var-hourglass-2: \\f252;\n$fa-var-microscope: \\f610;\n$fa-var-sink: \\e06d;\n$fa-var-bag-shopping: \\f290;\n$fa-var-shopping-bag: \\f290;\n$fa-var-arrow-down-z-a: \\f881;\n$fa-var-sort-alpha-desc: \\f881;\n$fa-var-sort-alpha-down-alt: \\f881;\n$fa-var-mitten: \\f7b5;\n$fa-var-person-rays: \\e54d;\n$fa-var-users: \\f0c0;\n$fa-var-eye-slash: \\f070;\n$fa-var-flask-vial: \\e4f3;\n$fa-var-hand: \\f256;\n$fa-var-hand-paper: \\f256;\n$fa-var-om: \\f679;\n$fa-var-worm: \\e599;\n$fa-var-house-circle-xmark: \\e50b;\n$fa-var-plug: \\f1e6;\n$fa-var-chevron-up: \\f077;\n$fa-var-hand-spock: \\f259;\n$fa-var-stopwatch: \\f2f2;\n$fa-var-face-kiss: \\f596;\n$fa-var-kiss: \\f596;\n$fa-var-bridge-circle-xmark: \\e4cb;\n$fa-var-face-grin-tongue: \\f589;\n$fa-var-grin-tongue: \\f589;\n$fa-var-chess-bishop: \\f43a;\n$fa-var-face-grin-wink: \\f58c;\n$fa-var-grin-wink: \\f58c;\n$fa-var-ear-deaf: \\f2a4;\n$fa-var-deaf: \\f2a4;\n$fa-var-deafness: \\f2a4;\n$fa-var-hard-of-hearing: \\f2a4;\n$fa-var-road-circle-check: \\e564;\n$fa-var-dice-five: \\f523;\n$fa-var-square-rss: \\f143;\n$fa-var-rss-square: \\f143;\n$fa-var-land-mine-on: \\e51b;\n$fa-var-i-cursor: \\f246;\n$fa-var-stamp: \\f5bf;\n$fa-var-stairs: \\e289;\n$fa-var-i: \\49;\n$fa-var-hryvnia-sign: \\f6f2;\n$fa-var-hryvnia: \\f6f2;\n$fa-var-pills: \\f484;\n$fa-var-face-grin-wide: \\f581;\n$fa-var-grin-alt: \\f581;\n$fa-var-tooth: \\f5c9;\n$fa-var-v: \\56;\n$fa-var-bangladeshi-taka-sign: \\e2e6;\n$fa-var-bicycle: \\f206;\n$fa-var-staff-snake: \\e579;\n$fa-var-rod-asclepius: \\e579;\n$fa-var-rod-snake: \\e579;\n$fa-var-staff-aesculapius: \\e579;\n$fa-var-head-side-cough-slash: \\e062;\n$fa-var-truck-medical: \\f0f9;\n$fa-var-ambulance: \\f0f9;\n$fa-var-wheat-awn-circle-exclamation: \\e598;\n$fa-var-snowman: \\f7d0;\n$fa-var-mortar-pestle: \\f5a7;\n$fa-var-road-barrier: \\e562;\n$fa-var-school: \\f549;\n$fa-var-igloo: \\f7ae;\n$fa-var-joint: \\f595;\n$fa-var-angle-right: \\f105;\n$fa-var-horse: \\f6f0;\n$fa-var-q: \\51;\n$fa-var-g: \\47;\n$fa-var-notes-medical: \\f481;\n$fa-var-temperature-half: \\f2c9;\n$fa-var-temperature-2: \\f2c9;\n$fa-var-thermometer-2: \\f2c9;\n$fa-var-thermometer-half: \\f2c9;\n$fa-var-dong-sign: \\e169;\n$fa-var-capsules: \\f46b;\n$fa-var-poo-storm: \\f75a;\n$fa-var-poo-bolt: \\f75a;\n$fa-var-face-frown-open: \\f57a;\n$fa-var-frown-open: \\f57a;\n$fa-var-hand-point-up: \\f0a6;\n$fa-var-money-bill: \\f0d6;\n$fa-var-bookmark: \\f02e;\n$fa-var-align-justify: \\f039;\n$fa-var-umbrella-beach: \\f5ca;\n$fa-var-helmet-un: \\e503;\n$fa-var-bullseye: \\f140;\n$fa-var-bacon: \\f7e5;\n$fa-var-hand-point-down: \\f0a7;\n$fa-var-arrow-up-from-bracket: \\e09a;\n$fa-var-folder: \\f07b;\n$fa-var-folder-blank: \\f07b;\n$fa-var-file-waveform: \\f478;\n$fa-var-file-medical-alt: \\f478;\n$fa-var-radiation: \\f7b9;\n$fa-var-chart-simple: \\e473;\n$fa-var-mars-stroke: \\f229;\n$fa-var-vial: \\f492;\n$fa-var-gauge: \\f624;\n$fa-var-dashboard: \\f624;\n$fa-var-gauge-med: \\f624;\n$fa-var-tachometer-alt-average: \\f624;\n$fa-var-wand-magic-sparkles: \\e2ca;\n$fa-var-magic-wand-sparkles: \\e2ca;\n$fa-var-e: \\45;\n$fa-var-pen-clip: \\f305;\n$fa-var-pen-alt: \\f305;\n$fa-var-bridge-circle-exclamation: \\e4ca;\n$fa-var-user: \\f007;\n$fa-var-school-circle-check: \\e56b;\n$fa-var-dumpster: \\f793;\n$fa-var-van-shuttle: \\f5b6;\n$fa-var-shuttle-van: \\f5b6;\n$fa-var-building-user: \\e4da;\n$fa-var-square-caret-left: \\f191;\n$fa-var-caret-square-left: \\f191;\n$fa-var-highlighter: \\f591;\n$fa-var-key: \\f084;\n$fa-var-bullhorn: \\f0a1;\n$fa-var-globe: \\f0ac;\n$fa-var-synagogue: \\f69b;\n$fa-var-person-half-dress: \\e548;\n$fa-var-road-bridge: \\e563;\n$fa-var-location-arrow: \\f124;\n$fa-var-c: \\43;\n$fa-var-tablet-button: \\f10a;\n$fa-var-building-lock: \\e4d6;\n$fa-var-pizza-slice: \\f818;\n$fa-var-money-bill-wave: \\f53a;\n$fa-var-chart-area: \\f1fe;\n$fa-var-area-chart: \\f1fe;\n$fa-var-house-flag: \\e50d;\n$fa-var-person-circle-minus: \\e540;\n$fa-var-ban: \\f05e;\n$fa-var-cancel: \\f05e;\n$fa-var-camera-rotate: \\e0d8;\n$fa-var-spray-can-sparkles: \\f5d0;\n$fa-var-air-freshener: \\f5d0;\n$fa-var-star: \\f005;\n$fa-var-repeat: \\f363;\n$fa-var-cross: \\f654;\n$fa-var-box: \\f466;\n$fa-var-venus-mars: \\f228;\n$fa-var-arrow-pointer: \\f245;\n$fa-var-mouse-pointer: \\f245;\n$fa-var-maximize: \\f31e;\n$fa-var-expand-arrows-alt: \\f31e;\n$fa-var-charging-station: \\f5e7;\n$fa-var-shapes: \\f61f;\n$fa-var-triangle-circle-square: \\f61f;\n$fa-var-shuffle: \\f074;\n$fa-var-random: \\f074;\n$fa-var-person-running: \\f70c;\n$fa-var-running: \\f70c;\n$fa-var-mobile-retro: \\e527;\n$fa-var-grip-lines-vertical: \\f7a5;\n$fa-var-spider: \\f717;\n$fa-var-hands-bound: \\e4f9;\n$fa-var-file-invoice-dollar: \\f571;\n$fa-var-plane-circle-exclamation: \\e556;\n$fa-var-x-ray: \\f497;\n$fa-var-spell-check: \\f891;\n$fa-var-slash: \\f715;\n$fa-var-computer-mouse: \\f8cc;\n$fa-var-mouse: \\f8cc;\n$fa-var-arrow-right-to-bracket: \\f090;\n$fa-var-sign-in: \\f090;\n$fa-var-shop-slash: \\e070;\n$fa-var-store-alt-slash: \\e070;\n$fa-var-server: \\f233;\n$fa-var-virus-covid-slash: \\e4a9;\n$fa-var-shop-lock: \\e4a5;\n$fa-var-hourglass-start: \\f251;\n$fa-var-hourglass-1: \\f251;\n$fa-var-blender-phone: \\f6b6;\n$fa-var-building-wheat: \\e4db;\n$fa-var-person-breastfeeding: \\e53a;\n$fa-var-right-to-bracket: \\f2f6;\n$fa-var-sign-in-alt: \\f2f6;\n$fa-var-venus: \\f221;\n$fa-var-passport: \\f5ab;\n$fa-var-thumbtack-slash: \\e68f;\n$fa-var-thumb-tack-slash: \\e68f;\n$fa-var-heart-pulse: \\f21e;\n$fa-var-heartbeat: \\f21e;\n$fa-var-people-carry-box: \\f4ce;\n$fa-var-people-carry: \\f4ce;\n$fa-var-temperature-high: \\f769;\n$fa-var-microchip: \\f2db;\n$fa-var-crown: \\f521;\n$fa-var-weight-hanging: \\f5cd;\n$fa-var-xmarks-lines: \\e59a;\n$fa-var-file-prescription: \\f572;\n$fa-var-weight-scale: \\f496;\n$fa-var-weight: \\f496;\n$fa-var-user-group: \\f500;\n$fa-var-user-friends: \\f500;\n$fa-var-arrow-up-a-z: \\f15e;\n$fa-var-sort-alpha-up: \\f15e;\n$fa-var-chess-knight: \\f441;\n$fa-var-face-laugh-squint: \\f59b;\n$fa-var-laugh-squint: \\f59b;\n$fa-var-wheelchair: \\f193;\n$fa-var-circle-arrow-up: \\f0aa;\n$fa-var-arrow-circle-up: \\f0aa;\n$fa-var-toggle-on: \\f205;\n$fa-var-person-walking: \\f554;\n$fa-var-walking: \\f554;\n$fa-var-l: \\4c;\n$fa-var-fire: \\f06d;\n$fa-var-bed-pulse: \\f487;\n$fa-var-procedures: \\f487;\n$fa-var-shuttle-space: \\f197;\n$fa-var-space-shuttle: \\f197;\n$fa-var-face-laugh: \\f599;\n$fa-var-laugh: \\f599;\n$fa-var-folder-open: \\f07c;\n$fa-var-heart-circle-plus: \\e500;\n$fa-var-code-fork: \\e13b;\n$fa-var-city: \\f64f;\n$fa-var-microphone-lines: \\f3c9;\n$fa-var-microphone-alt: \\f3c9;\n$fa-var-pepper-hot: \\f816;\n$fa-var-unlock: \\f09c;\n$fa-var-colon-sign: \\e140;\n$fa-var-headset: \\f590;\n$fa-var-store-slash: \\e071;\n$fa-var-road-circle-xmark: \\e566;\n$fa-var-user-minus: \\f503;\n$fa-var-mars-stroke-up: \\f22a;\n$fa-var-mars-stroke-v: \\f22a;\n$fa-var-champagne-glasses: \\f79f;\n$fa-var-glass-cheers: \\f79f;\n$fa-var-clipboard: \\f328;\n$fa-var-house-circle-exclamation: \\e50a;\n$fa-var-file-arrow-up: \\f574;\n$fa-var-file-upload: \\f574;\n$fa-var-wifi: \\f1eb;\n$fa-var-wifi-3: \\f1eb;\n$fa-var-wifi-strong: \\f1eb;\n$fa-var-bath: \\f2cd;\n$fa-var-bathtub: \\f2cd;\n$fa-var-underline: \\f0cd;\n$fa-var-user-pen: \\f4ff;\n$fa-var-user-edit: \\f4ff;\n$fa-var-signature: \\f5b7;\n$fa-var-stroopwafel: \\f551;\n$fa-var-bold: \\f032;\n$fa-var-anchor-lock: \\e4ad;\n$fa-var-building-ngo: \\e4d7;\n$fa-var-manat-sign: \\e1d5;\n$fa-var-not-equal: \\f53e;\n$fa-var-border-top-left: \\f853;\n$fa-var-border-style: \\f853;\n$fa-var-map-location-dot: \\f5a0;\n$fa-var-map-marked-alt: \\f5a0;\n$fa-var-jedi: \\f669;\n$fa-var-square-poll-vertical: \\f681;\n$fa-var-poll: \\f681;\n$fa-var-mug-hot: \\f7b6;\n$fa-var-car-battery: \\f5df;\n$fa-var-battery-car: \\f5df;\n$fa-var-gift: \\f06b;\n$fa-var-dice-two: \\f528;\n$fa-var-chess-queen: \\f445;\n$fa-var-glasses: \\f530;\n$fa-var-chess-board: \\f43c;\n$fa-var-building-circle-check: \\e4d2;\n$fa-var-person-chalkboard: \\e53d;\n$fa-var-mars-stroke-right: \\f22b;\n$fa-var-mars-stroke-h: \\f22b;\n$fa-var-hand-back-fist: \\f255;\n$fa-var-hand-rock: \\f255;\n$fa-var-square-caret-up: \\f151;\n$fa-var-caret-square-up: \\f151;\n$fa-var-cloud-showers-water: \\e4e4;\n$fa-var-chart-bar: \\f080;\n$fa-var-bar-chart: \\f080;\n$fa-var-hands-bubbles: \\e05e;\n$fa-var-hands-wash: \\e05e;\n$fa-var-less-than-equal: \\f537;\n$fa-var-train: \\f238;\n$fa-var-eye-low-vision: \\f2a8;\n$fa-var-low-vision: \\f2a8;\n$fa-var-crow: \\f520;\n$fa-var-sailboat: \\e445;\n$fa-var-window-restore: \\f2d2;\n$fa-var-square-plus: \\f0fe;\n$fa-var-plus-square: \\f0fe;\n$fa-var-torii-gate: \\f6a1;\n$fa-var-frog: \\f52e;\n$fa-var-bucket: \\e4cf;\n$fa-var-image: \\f03e;\n$fa-var-microphone: \\f130;\n$fa-var-cow: \\f6c8;\n$fa-var-caret-up: \\f0d8;\n$fa-var-screwdriver: \\f54a;\n$fa-var-folder-closed: \\e185;\n$fa-var-house-tsunami: \\e515;\n$fa-var-square-nfi: \\e576;\n$fa-var-arrow-up-from-ground-water: \\e4b5;\n$fa-var-martini-glass: \\f57b;\n$fa-var-glass-martini-alt: \\f57b;\n$fa-var-square-binary: \\e69b;\n$fa-var-rotate-left: \\f2ea;\n$fa-var-rotate-back: \\f2ea;\n$fa-var-rotate-backward: \\f2ea;\n$fa-var-undo-alt: \\f2ea;\n$fa-var-table-columns: \\f0db;\n$fa-var-columns: \\f0db;\n$fa-var-lemon: \\f094;\n$fa-var-head-side-mask: \\e063;\n$fa-var-handshake: \\f2b5;\n$fa-var-gem: \\f3a5;\n$fa-var-dolly: \\f472;\n$fa-var-dolly-box: \\f472;\n$fa-var-smoking: \\f48d;\n$fa-var-minimize: \\f78c;\n$fa-var-compress-arrows-alt: \\f78c;\n$fa-var-monument: \\f5a6;\n$fa-var-snowplow: \\f7d2;\n$fa-var-angles-right: \\f101;\n$fa-var-angle-double-right: \\f101;\n$fa-var-cannabis: \\f55f;\n$fa-var-circle-play: \\f144;\n$fa-var-play-circle: \\f144;\n$fa-var-tablets: \\f490;\n$fa-var-ethernet: \\f796;\n$fa-var-euro-sign: \\f153;\n$fa-var-eur: \\f153;\n$fa-var-euro: \\f153;\n$fa-var-chair: \\f6c0;\n$fa-var-circle-check: \\f058;\n$fa-var-check-circle: \\f058;\n$fa-var-circle-stop: \\f28d;\n$fa-var-stop-circle: \\f28d;\n$fa-var-compass-drafting: \\f568;\n$fa-var-drafting-compass: \\f568;\n$fa-var-plate-wheat: \\e55a;\n$fa-var-icicles: \\f7ad;\n$fa-var-person-shelter: \\e54f;\n$fa-var-neuter: \\f22c;\n$fa-var-id-badge: \\f2c1;\n$fa-var-marker: \\f5a1;\n$fa-var-face-laugh-beam: \\f59a;\n$fa-var-laugh-beam: \\f59a;\n$fa-var-helicopter-symbol: \\e502;\n$fa-var-universal-access: \\f29a;\n$fa-var-circle-chevron-up: \\f139;\n$fa-var-chevron-circle-up: \\f139;\n$fa-var-lari-sign: \\e1c8;\n$fa-var-volcano: \\f770;\n$fa-var-person-walking-dashed-line-arrow-right: \\e553;\n$fa-var-sterling-sign: \\f154;\n$fa-var-gbp: \\f154;\n$fa-var-pound-sign: \\f154;\n$fa-var-viruses: \\e076;\n$fa-var-square-person-confined: \\e577;\n$fa-var-user-tie: \\f508;\n$fa-var-arrow-down-long: \\f175;\n$fa-var-long-arrow-down: \\f175;\n$fa-var-tent-arrow-down-to-line: \\e57e;\n$fa-var-certificate: \\f0a3;\n$fa-var-reply-all: \\f122;\n$fa-var-mail-reply-all: \\f122;\n$fa-var-suitcase: \\f0f2;\n$fa-var-person-skating: \\f7c5;\n$fa-var-skating: \\f7c5;\n$fa-var-filter-circle-dollar: \\f662;\n$fa-var-funnel-dollar: \\f662;\n$fa-var-camera-retro: \\f083;\n$fa-var-circle-arrow-down: \\f0ab;\n$fa-var-arrow-circle-down: \\f0ab;\n$fa-var-file-import: \\f56f;\n$fa-var-arrow-right-to-file: \\f56f;\n$fa-var-square-arrow-up-right: \\f14c;\n$fa-var-external-link-square: \\f14c;\n$fa-var-box-open: \\f49e;\n$fa-var-scroll: \\f70e;\n$fa-var-spa: \\f5bb;\n$fa-var-location-pin-lock: \\e51f;\n$fa-var-pause: \\f04c;\n$fa-var-hill-avalanche: \\e507;\n$fa-var-temperature-empty: \\f2cb;\n$fa-var-temperature-0: \\f2cb;\n$fa-var-thermometer-0: \\f2cb;\n$fa-var-thermometer-empty: \\f2cb;\n$fa-var-bomb: \\f1e2;\n$fa-var-registered: \\f25d;\n$fa-var-address-card: \\f2bb;\n$fa-var-contact-card: \\f2bb;\n$fa-var-vcard: \\f2bb;\n$fa-var-scale-unbalanced-flip: \\f516;\n$fa-var-balance-scale-right: \\f516;\n$fa-var-subscript: \\f12c;\n$fa-var-diamond-turn-right: \\f5eb;\n$fa-var-directions: \\f5eb;\n$fa-var-burst: \\e4dc;\n$fa-var-house-laptop: \\e066;\n$fa-var-laptop-house: \\e066;\n$fa-var-face-tired: \\f5c8;\n$fa-var-tired: \\f5c8;\n$fa-var-money-bills: \\e1f3;\n$fa-var-smog: \\f75f;\n$fa-var-crutch: \\f7f7;\n$fa-var-cloud-arrow-up: \\f0ee;\n$fa-var-cloud-upload: \\f0ee;\n$fa-var-cloud-upload-alt: \\f0ee;\n$fa-var-palette: \\f53f;\n$fa-var-arrows-turn-right: \\e4c0;\n$fa-var-vest: \\e085;\n$fa-var-ferry: \\e4ea;\n$fa-var-arrows-down-to-people: \\e4b9;\n$fa-var-seedling: \\f4d8;\n$fa-var-sprout: \\f4d8;\n$fa-var-left-right: \\f337;\n$fa-var-arrows-alt-h: \\f337;\n$fa-var-boxes-packing: \\e4c7;\n$fa-var-circle-arrow-left: \\f0a8;\n$fa-var-arrow-circle-left: \\f0a8;\n$fa-var-group-arrows-rotate: \\e4f6;\n$fa-var-bowl-food: \\e4c6;\n$fa-var-candy-cane: \\f786;\n$fa-var-arrow-down-wide-short: \\f160;\n$fa-var-sort-amount-asc: \\f160;\n$fa-var-sort-amount-down: \\f160;\n$fa-var-cloud-bolt: \\f76c;\n$fa-var-thunderstorm: \\f76c;\n$fa-var-text-slash: \\f87d;\n$fa-var-remove-format: \\f87d;\n$fa-var-face-smile-wink: \\f4da;\n$fa-var-smile-wink: \\f4da;\n$fa-var-file-word: \\f1c2;\n$fa-var-file-powerpoint: \\f1c4;\n$fa-var-arrows-left-right: \\f07e;\n$fa-var-arrows-h: \\f07e;\n$fa-var-house-lock: \\e510;\n$fa-var-cloud-arrow-down: \\f0ed;\n$fa-var-cloud-download: \\f0ed;\n$fa-var-cloud-download-alt: \\f0ed;\n$fa-var-children: \\e4e1;\n$fa-var-chalkboard: \\f51b;\n$fa-var-blackboard: \\f51b;\n$fa-var-user-large-slash: \\f4fa;\n$fa-var-user-alt-slash: \\f4fa;\n$fa-var-envelope-open: \\f2b6;\n$fa-var-handshake-simple-slash: \\e05f;\n$fa-var-handshake-alt-slash: \\e05f;\n$fa-var-mattress-pillow: \\e525;\n$fa-var-guarani-sign: \\e19a;\n$fa-var-arrows-rotate: \\f021;\n$fa-var-refresh: \\f021;\n$fa-var-sync: \\f021;\n$fa-var-fire-extinguisher: \\f134;\n$fa-var-cruzeiro-sign: \\e152;\n$fa-var-greater-than-equal: \\f532;\n$fa-var-shield-halved: \\f3ed;\n$fa-var-shield-alt: \\f3ed;\n$fa-var-book-atlas: \\f558;\n$fa-var-atlas: \\f558;\n$fa-var-virus: \\e074;\n$fa-var-envelope-circle-check: \\e4e8;\n$fa-var-layer-group: \\f5fd;\n$fa-var-arrows-to-dot: \\e4be;\n$fa-var-archway: \\f557;\n$fa-var-heart-circle-check: \\e4fd;\n$fa-var-house-chimney-crack: \\f6f1;\n$fa-var-house-damage: \\f6f1;\n$fa-var-file-zipper: \\f1c6;\n$fa-var-file-archive: \\f1c6;\n$fa-var-square: \\f0c8;\n$fa-var-martini-glass-empty: \\f000;\n$fa-var-glass-martini: \\f000;\n$fa-var-couch: \\f4b8;\n$fa-var-cedi-sign: \\e0df;\n$fa-var-italic: \\f033;\n$fa-var-table-cells-column-lock: \\e678;\n$fa-var-church: \\f51d;\n$fa-var-comments-dollar: \\f653;\n$fa-var-democrat: \\f747;\n$fa-var-z: \\5a;\n$fa-var-person-skiing: \\f7c9;\n$fa-var-skiing: \\f7c9;\n$fa-var-road-lock: \\e567;\n$fa-var-a: \\41;\n$fa-var-temperature-arrow-down: \\e03f;\n$fa-var-temperature-down: \\e03f;\n$fa-var-feather-pointed: \\f56b;\n$fa-var-feather-alt: \\f56b;\n$fa-var-p: \\50;\n$fa-var-snowflake: \\f2dc;\n$fa-var-newspaper: \\f1ea;\n$fa-var-rectangle-ad: \\f641;\n$fa-var-ad: \\f641;\n$fa-var-circle-arrow-right: \\f0a9;\n$fa-var-arrow-circle-right: \\f0a9;\n$fa-var-filter-circle-xmark: \\e17b;\n$fa-var-locust: \\e520;\n$fa-var-sort: \\f0dc;\n$fa-var-unsorted: \\f0dc;\n$fa-var-list-ol: \\f0cb;\n$fa-var-list-1-2: \\f0cb;\n$fa-var-list-numeric: \\f0cb;\n$fa-var-person-dress-burst: \\e544;\n$fa-var-money-check-dollar: \\f53d;\n$fa-var-money-check-alt: \\f53d;\n$fa-var-vector-square: \\f5cb;\n$fa-var-bread-slice: \\f7ec;\n$fa-var-language: \\f1ab;\n$fa-var-face-kiss-wink-heart: \\f598;\n$fa-var-kiss-wink-heart: \\f598;\n$fa-var-filter: \\f0b0;\n$fa-var-question: \\3f;\n$fa-var-file-signature: \\f573;\n$fa-var-up-down-left-right: \\f0b2;\n$fa-var-arrows-alt: \\f0b2;\n$fa-var-house-chimney-user: \\e065;\n$fa-var-hand-holding-heart: \\f4be;\n$fa-var-puzzle-piece: \\f12e;\n$fa-var-money-check: \\f53c;\n$fa-var-star-half-stroke: \\f5c0;\n$fa-var-star-half-alt: \\f5c0;\n$fa-var-code: \\f121;\n$fa-var-whiskey-glass: \\f7a0;\n$fa-var-glass-whiskey: \\f7a0;\n$fa-var-building-circle-exclamation: \\e4d3;\n$fa-var-magnifying-glass-chart: \\e522;\n$fa-var-arrow-up-right-from-square: \\f08e;\n$fa-var-external-link: \\f08e;\n$fa-var-cubes-stacked: \\e4e6;\n$fa-var-won-sign: \\f159;\n$fa-var-krw: \\f159;\n$fa-var-won: \\f159;\n$fa-var-virus-covid: \\e4a8;\n$fa-var-austral-sign: \\e0a9;\n$fa-var-f: \\46;\n$fa-var-leaf: \\f06c;\n$fa-var-road: \\f018;\n$fa-var-taxi: \\f1ba;\n$fa-var-cab: \\f1ba;\n$fa-var-person-circle-plus: \\e541;\n$fa-var-chart-pie: \\f200;\n$fa-var-pie-chart: \\f200;\n$fa-var-bolt-lightning: \\e0b7;\n$fa-var-sack-xmark: \\e56a;\n$fa-var-file-excel: \\f1c3;\n$fa-var-file-contract: \\f56c;\n$fa-var-fish-fins: \\e4f2;\n$fa-var-building-flag: \\e4d5;\n$fa-var-face-grin-beam: \\f582;\n$fa-var-grin-beam: \\f582;\n$fa-var-object-ungroup: \\f248;\n$fa-var-poop: \\f619;\n$fa-var-location-pin: \\f041;\n$fa-var-map-marker: \\f041;\n$fa-var-kaaba: \\f66b;\n$fa-var-toilet-paper: \\f71e;\n$fa-var-helmet-safety: \\f807;\n$fa-var-hard-hat: \\f807;\n$fa-var-hat-hard: \\f807;\n$fa-var-eject: \\f052;\n$fa-var-circle-right: \\f35a;\n$fa-var-arrow-alt-circle-right: \\f35a;\n$fa-var-plane-circle-check: \\e555;\n$fa-var-face-rolling-eyes: \\f5a5;\n$fa-var-meh-rolling-eyes: \\f5a5;\n$fa-var-object-group: \\f247;\n$fa-var-chart-line: \\f201;\n$fa-var-line-chart: \\f201;\n$fa-var-mask-ventilator: \\e524;\n$fa-var-arrow-right: \\f061;\n$fa-var-signs-post: \\f277;\n$fa-var-map-signs: \\f277;\n$fa-var-cash-register: \\f788;\n$fa-var-person-circle-question: \\e542;\n$fa-var-h: \\48;\n$fa-var-tarp: \\e57b;\n$fa-var-screwdriver-wrench: \\f7d9;\n$fa-var-tools: \\f7d9;\n$fa-var-arrows-to-eye: \\e4bf;\n$fa-var-plug-circle-bolt: \\e55b;\n$fa-var-heart: \\f004;\n$fa-var-mars-and-venus: \\f224;\n$fa-var-house-user: \\e1b0;\n$fa-var-home-user: \\e1b0;\n$fa-var-dumpster-fire: \\f794;\n$fa-var-house-crack: \\e3b1;\n$fa-var-martini-glass-citrus: \\f561;\n$fa-var-cocktail: \\f561;\n$fa-var-face-surprise: \\f5c2;\n$fa-var-surprise: \\f5c2;\n$fa-var-bottle-water: \\e4c5;\n$fa-var-circle-pause: \\f28b;\n$fa-var-pause-circle: \\f28b;\n$fa-var-toilet-paper-slash: \\e072;\n$fa-var-apple-whole: \\f5d1;\n$fa-var-apple-alt: \\f5d1;\n$fa-var-kitchen-set: \\e51a;\n$fa-var-r: \\52;\n$fa-var-temperature-quarter: \\f2ca;\n$fa-var-temperature-1: \\f2ca;\n$fa-var-thermometer-1: \\f2ca;\n$fa-var-thermometer-quarter: \\f2ca;\n$fa-var-cube: \\f1b2;\n$fa-var-bitcoin-sign: \\e0b4;\n$fa-var-shield-dog: \\e573;\n$fa-var-solar-panel: \\f5ba;\n$fa-var-lock-open: \\f3c1;\n$fa-var-elevator: \\e16d;\n$fa-var-money-bill-transfer: \\e528;\n$fa-var-money-bill-trend-up: \\e529;\n$fa-var-house-flood-water-circle-arrow-right: \\e50f;\n$fa-var-square-poll-horizontal: \\f682;\n$fa-var-poll-h: \\f682;\n$fa-var-circle: \\f111;\n$fa-var-backward-fast: \\f049;\n$fa-var-fast-backward: \\f049;\n$fa-var-recycle: \\f1b8;\n$fa-var-user-astronaut: \\f4fb;\n$fa-var-plane-slash: \\e069;\n$fa-var-trademark: \\f25c;\n$fa-var-basketball: \\f434;\n$fa-var-basketball-ball: \\f434;\n$fa-var-satellite-dish: \\f7c0;\n$fa-var-circle-up: \\f35b;\n$fa-var-arrow-alt-circle-up: \\f35b;\n$fa-var-mobile-screen-button: \\f3cd;\n$fa-var-mobile-alt: \\f3cd;\n$fa-var-volume-high: \\f028;\n$fa-var-volume-up: \\f028;\n$fa-var-users-rays: \\e593;\n$fa-var-wallet: \\f555;\n$fa-var-clipboard-check: \\f46c;\n$fa-var-file-audio: \\f1c7;\n$fa-var-burger: \\f805;\n$fa-var-hamburger: \\f805;\n$fa-var-wrench: \\f0ad;\n$fa-var-bugs: \\e4d0;\n$fa-var-rupee-sign: \\f156;\n$fa-var-rupee: \\f156;\n$fa-var-file-image: \\f1c5;\n$fa-var-circle-question: \\f059;\n$fa-var-question-circle: \\f059;\n$fa-var-plane-departure: \\f5b0;\n$fa-var-handshake-slash: \\e060;\n$fa-var-book-bookmark: \\e0bb;\n$fa-var-code-branch: \\f126;\n$fa-var-hat-cowboy: \\f8c0;\n$fa-var-bridge: \\e4c8;\n$fa-var-phone-flip: \\f879;\n$fa-var-phone-alt: \\f879;\n$fa-var-truck-front: \\e2b7;\n$fa-var-cat: \\f6be;\n$fa-var-anchor-circle-exclamation: \\e4ab;\n$fa-var-truck-field: \\e58d;\n$fa-var-route: \\f4d7;\n$fa-var-clipboard-question: \\e4e3;\n$fa-var-panorama: \\e209;\n$fa-var-comment-medical: \\f7f5;\n$fa-var-teeth-open: \\f62f;\n$fa-var-file-circle-minus: \\e4ed;\n$fa-var-tags: \\f02c;\n$fa-var-wine-glass: \\f4e3;\n$fa-var-forward-fast: \\f050;\n$fa-var-fast-forward: \\f050;\n$fa-var-face-meh-blank: \\f5a4;\n$fa-var-meh-blank: \\f5a4;\n$fa-var-square-parking: \\f540;\n$fa-var-parking: \\f540;\n$fa-var-house-signal: \\e012;\n$fa-var-bars-progress: \\f828;\n$fa-var-tasks-alt: \\f828;\n$fa-var-faucet-drip: \\e006;\n$fa-var-cart-flatbed: \\f474;\n$fa-var-dolly-flatbed: \\f474;\n$fa-var-ban-smoking: \\f54d;\n$fa-var-smoking-ban: \\f54d;\n$fa-var-terminal: \\f120;\n$fa-var-mobile-button: \\f10b;\n$fa-var-house-medical-flag: \\e514;\n$fa-var-basket-shopping: \\f291;\n$fa-var-shopping-basket: \\f291;\n$fa-var-tape: \\f4db;\n$fa-var-bus-simple: \\f55e;\n$fa-var-bus-alt: \\f55e;\n$fa-var-eye: \\f06e;\n$fa-var-face-sad-cry: \\f5b3;\n$fa-var-sad-cry: \\f5b3;\n$fa-var-audio-description: \\f29e;\n$fa-var-person-military-to-person: \\e54c;\n$fa-var-file-shield: \\e4f0;\n$fa-var-user-slash: \\f506;\n$fa-var-pen: \\f304;\n$fa-var-tower-observation: \\e586;\n$fa-var-file-code: \\f1c9;\n$fa-var-signal: \\f012;\n$fa-var-signal-5: \\f012;\n$fa-var-signal-perfect: \\f012;\n$fa-var-bus: \\f207;\n$fa-var-heart-circle-xmark: \\e501;\n$fa-var-house-chimney: \\e3af;\n$fa-var-home-lg: \\e3af;\n$fa-var-window-maximize: \\f2d0;\n$fa-var-face-frown: \\f119;\n$fa-var-frown: \\f119;\n$fa-var-prescription: \\f5b1;\n$fa-var-shop: \\f54f;\n$fa-var-store-alt: \\f54f;\n$fa-var-floppy-disk: \\f0c7;\n$fa-var-save: \\f0c7;\n$fa-var-vihara: \\f6a7;\n$fa-var-scale-unbalanced: \\f515;\n$fa-var-balance-scale-left: \\f515;\n$fa-var-sort-up: \\f0de;\n$fa-var-sort-asc: \\f0de;\n$fa-var-comment-dots: \\f4ad;\n$fa-var-commenting: \\f4ad;\n$fa-var-plant-wilt: \\e5aa;\n$fa-var-diamond: \\f219;\n$fa-var-face-grin-squint: \\f585;\n$fa-var-grin-squint: \\f585;\n$fa-var-hand-holding-dollar: \\f4c0;\n$fa-var-hand-holding-usd: \\f4c0;\n$fa-var-chart-diagram: \\e695;\n$fa-var-bacterium: \\e05a;\n$fa-var-hand-pointer: \\f25a;\n$fa-var-drum-steelpan: \\f56a;\n$fa-var-hand-scissors: \\f257;\n$fa-var-hands-praying: \\f684;\n$fa-var-praying-hands: \\f684;\n$fa-var-arrow-rotate-right: \\f01e;\n$fa-var-arrow-right-rotate: \\f01e;\n$fa-var-arrow-rotate-forward: \\f01e;\n$fa-var-redo: \\f01e;\n$fa-var-biohazard: \\f780;\n$fa-var-location-crosshairs: \\f601;\n$fa-var-location: \\f601;\n$fa-var-mars-double: \\f227;\n$fa-var-child-dress: \\e59c;\n$fa-var-users-between-lines: \\e591;\n$fa-var-lungs-virus: \\e067;\n$fa-var-face-grin-tears: \\f588;\n$fa-var-grin-tears: \\f588;\n$fa-var-phone: \\f095;\n$fa-var-calendar-xmark: \\f273;\n$fa-var-calendar-times: \\f273;\n$fa-var-child-reaching: \\e59d;\n$fa-var-head-side-virus: \\e064;\n$fa-var-user-gear: \\f4fe;\n$fa-var-user-cog: \\f4fe;\n$fa-var-arrow-up-1-9: \\f163;\n$fa-var-sort-numeric-up: \\f163;\n$fa-var-door-closed: \\f52a;\n$fa-var-shield-virus: \\e06c;\n$fa-var-dice-six: \\f526;\n$fa-var-mosquito-net: \\e52c;\n$fa-var-file-fragment: \\e697;\n$fa-var-bridge-water: \\e4ce;\n$fa-var-person-booth: \\f756;\n$fa-var-text-width: \\f035;\n$fa-var-hat-wizard: \\f6e8;\n$fa-var-pen-fancy: \\f5ac;\n$fa-var-person-digging: \\f85e;\n$fa-var-digging: \\f85e;\n$fa-var-trash: \\f1f8;\n$fa-var-gauge-simple: \\f629;\n$fa-var-gauge-simple-med: \\f629;\n$fa-var-tachometer-average: \\f629;\n$fa-var-book-medical: \\f7e6;\n$fa-var-poo: \\f2fe;\n$fa-var-quote-right: \\f10e;\n$fa-var-quote-right-alt: \\f10e;\n$fa-var-shirt: \\f553;\n$fa-var-t-shirt: \\f553;\n$fa-var-tshirt: \\f553;\n$fa-var-cubes: \\f1b3;\n$fa-var-divide: \\f529;\n$fa-var-tenge-sign: \\f7d7;\n$fa-var-tenge: \\f7d7;\n$fa-var-headphones: \\f025;\n$fa-var-hands-holding: \\f4c2;\n$fa-var-hands-clapping: \\e1a8;\n$fa-var-republican: \\f75e;\n$fa-var-arrow-left: \\f060;\n$fa-var-person-circle-xmark: \\e543;\n$fa-var-ruler: \\f545;\n$fa-var-align-left: \\f036;\n$fa-var-dice-d6: \\f6d1;\n$fa-var-restroom: \\f7bd;\n$fa-var-j: \\4a;\n$fa-var-users-viewfinder: \\e595;\n$fa-var-file-video: \\f1c8;\n$fa-var-up-right-from-square: \\f35d;\n$fa-var-external-link-alt: \\f35d;\n$fa-var-table-cells: \\f00a;\n$fa-var-th: \\f00a;\n$fa-var-file-pdf: \\f1c1;\n$fa-var-book-bible: \\f647;\n$fa-var-bible: \\f647;\n$fa-var-o: \\4f;\n$fa-var-suitcase-medical: \\f0fa;\n$fa-var-medkit: \\f0fa;\n$fa-var-user-secret: \\f21b;\n$fa-var-otter: \\f700;\n$fa-var-person-dress: \\f182;\n$fa-var-female: \\f182;\n$fa-var-comment-dollar: \\f651;\n$fa-var-business-time: \\f64a;\n$fa-var-briefcase-clock: \\f64a;\n$fa-var-table-cells-large: \\f009;\n$fa-var-th-large: \\f009;\n$fa-var-book-tanakh: \\f827;\n$fa-var-tanakh: \\f827;\n$fa-var-phone-volume: \\f2a0;\n$fa-var-volume-control-phone: \\f2a0;\n$fa-var-hat-cowboy-side: \\f8c1;\n$fa-var-clipboard-user: \\f7f3;\n$fa-var-child: \\f1ae;\n$fa-var-lira-sign: \\f195;\n$fa-var-satellite: \\f7bf;\n$fa-var-plane-lock: \\e558;\n$fa-var-tag: \\f02b;\n$fa-var-comment: \\f075;\n$fa-var-cake-candles: \\f1fd;\n$fa-var-birthday-cake: \\f1fd;\n$fa-var-cake: \\f1fd;\n$fa-var-envelope: \\f0e0;\n$fa-var-angles-up: \\f102;\n$fa-var-angle-double-up: \\f102;\n$fa-var-paperclip: \\f0c6;\n$fa-var-arrow-right-to-city: \\e4b3;\n$fa-var-ribbon: \\f4d6;\n$fa-var-lungs: \\f604;\n$fa-var-arrow-up-9-1: \\f887;\n$fa-var-sort-numeric-up-alt: \\f887;\n$fa-var-litecoin-sign: \\e1d3;\n$fa-var-border-none: \\f850;\n$fa-var-circle-nodes: \\e4e2;\n$fa-var-parachute-box: \\f4cd;\n$fa-var-indent: \\f03c;\n$fa-var-truck-field-un: \\e58e;\n$fa-var-hourglass: \\f254;\n$fa-var-hourglass-empty: \\f254;\n$fa-var-mountain: \\f6fc;\n$fa-var-user-doctor: \\f0f0;\n$fa-var-user-md: \\f0f0;\n$fa-var-circle-info: \\f05a;\n$fa-var-info-circle: \\f05a;\n$fa-var-cloud-meatball: \\f73b;\n$fa-var-camera: \\f030;\n$fa-var-camera-alt: \\f030;\n$fa-var-square-virus: \\e578;\n$fa-var-meteor: \\f753;\n$fa-var-car-on: \\e4dd;\n$fa-var-sleigh: \\f7cc;\n$fa-var-arrow-down-1-9: \\f162;\n$fa-var-sort-numeric-asc: \\f162;\n$fa-var-sort-numeric-down: \\f162;\n$fa-var-hand-holding-droplet: \\f4c1;\n$fa-var-hand-holding-water: \\f4c1;\n$fa-var-water: \\f773;\n$fa-var-calendar-check: \\f274;\n$fa-var-braille: \\f2a1;\n$fa-var-prescription-bottle-medical: \\f486;\n$fa-var-prescription-bottle-alt: \\f486;\n$fa-var-landmark: \\f66f;\n$fa-var-truck: \\f0d1;\n$fa-var-crosshairs: \\f05b;\n$fa-var-person-cane: \\e53c;\n$fa-var-tent: \\e57d;\n$fa-var-vest-patches: \\e086;\n$fa-var-check-double: \\f560;\n$fa-var-arrow-down-a-z: \\f15d;\n$fa-var-sort-alpha-asc: \\f15d;\n$fa-var-sort-alpha-down: \\f15d;\n$fa-var-money-bill-wheat: \\e52a;\n$fa-var-cookie: \\f563;\n$fa-var-arrow-rotate-left: \\f0e2;\n$fa-var-arrow-left-rotate: \\f0e2;\n$fa-var-arrow-rotate-back: \\f0e2;\n$fa-var-arrow-rotate-backward: \\f0e2;\n$fa-var-undo: \\f0e2;\n$fa-var-hard-drive: \\f0a0;\n$fa-var-hdd: \\f0a0;\n$fa-var-face-grin-squint-tears: \\f586;\n$fa-var-grin-squint-tears: \\f586;\n$fa-var-dumbbell: \\f44b;\n$fa-var-rectangle-list: \\f022;\n$fa-var-list-alt: \\f022;\n$fa-var-tarp-droplet: \\e57c;\n$fa-var-house-medical-circle-check: \\e511;\n$fa-var-person-skiing-nordic: \\f7ca;\n$fa-var-skiing-nordic: \\f7ca;\n$fa-var-calendar-plus: \\f271;\n$fa-var-plane-arrival: \\f5af;\n$fa-var-circle-left: \\f359;\n$fa-var-arrow-alt-circle-left: \\f359;\n$fa-var-train-subway: \\f239;\n$fa-var-subway: \\f239;\n$fa-var-chart-gantt: \\e0e4;\n$fa-var-indian-rupee-sign: \\e1bc;\n$fa-var-indian-rupee: \\e1bc;\n$fa-var-inr: \\e1bc;\n$fa-var-crop-simple: \\f565;\n$fa-var-crop-alt: \\f565;\n$fa-var-money-bill-1: \\f3d1;\n$fa-var-money-bill-alt: \\f3d1;\n$fa-var-left-long: \\f30a;\n$fa-var-long-arrow-alt-left: \\f30a;\n$fa-var-dna: \\f471;\n$fa-var-virus-slash: \\e075;\n$fa-var-minus: \\f068;\n$fa-var-subtract: \\f068;\n$fa-var-chess: \\f439;\n$fa-var-arrow-left-long: \\f177;\n$fa-var-long-arrow-left: \\f177;\n$fa-var-plug-circle-check: \\e55c;\n$fa-var-street-view: \\f21d;\n$fa-var-franc-sign: \\e18f;\n$fa-var-volume-off: \\f026;\n$fa-var-hands-asl-interpreting: \\f2a3;\n$fa-var-american-sign-language-interpreting: \\f2a3;\n$fa-var-asl-interpreting: \\f2a3;\n$fa-var-hands-american-sign-language-interpreting: \\f2a3;\n$fa-var-gear: \\f013;\n$fa-var-cog: \\f013;\n$fa-var-droplet-slash: \\f5c7;\n$fa-var-tint-slash: \\f5c7;\n$fa-var-mosque: \\f678;\n$fa-var-mosquito: \\e52b;\n$fa-var-star-of-david: \\f69a;\n$fa-var-person-military-rifle: \\e54b;\n$fa-var-cart-shopping: \\f07a;\n$fa-var-shopping-cart: \\f07a;\n$fa-var-vials: \\f493;\n$fa-var-plug-circle-plus: \\e55f;\n$fa-var-place-of-worship: \\f67f;\n$fa-var-grip-vertical: \\f58e;\n$fa-var-hexagon-nodes: \\e699;\n$fa-var-arrow-turn-up: \\f148;\n$fa-var-level-up: \\f148;\n$fa-var-u: \\55;\n$fa-var-square-root-variable: \\f698;\n$fa-var-square-root-alt: \\f698;\n$fa-var-clock: \\f017;\n$fa-var-clock-four: \\f017;\n$fa-var-backward-step: \\f048;\n$fa-var-step-backward: \\f048;\n$fa-var-pallet: \\f482;\n$fa-var-faucet: \\e005;\n$fa-var-baseball-bat-ball: \\f432;\n$fa-var-s: \\53;\n$fa-var-timeline: \\e29c;\n$fa-var-keyboard: \\f11c;\n$fa-var-caret-down: \\f0d7;\n$fa-var-house-chimney-medical: \\f7f2;\n$fa-var-clinic-medical: \\f7f2;\n$fa-var-temperature-three-quarters: \\f2c8;\n$fa-var-temperature-3: \\f2c8;\n$fa-var-thermometer-3: \\f2c8;\n$fa-var-thermometer-three-quarters: \\f2c8;\n$fa-var-mobile-screen: \\f3cf;\n$fa-var-mobile-android-alt: \\f3cf;\n$fa-var-plane-up: \\e22d;\n$fa-var-piggy-bank: \\f4d3;\n$fa-var-battery-half: \\f242;\n$fa-var-battery-3: \\f242;\n$fa-var-mountain-city: \\e52e;\n$fa-var-coins: \\f51e;\n$fa-var-khanda: \\f66d;\n$fa-var-sliders: \\f1de;\n$fa-var-sliders-h: \\f1de;\n$fa-var-folder-tree: \\f802;\n$fa-var-network-wired: \\f6ff;\n$fa-var-map-pin: \\f276;\n$fa-var-hamsa: \\f665;\n$fa-var-cent-sign: \\e3f5;\n$fa-var-flask: \\f0c3;\n$fa-var-person-pregnant: \\e31e;\n$fa-var-wand-sparkles: \\f72b;\n$fa-var-ellipsis-vertical: \\f142;\n$fa-var-ellipsis-v: \\f142;\n$fa-var-ticket: \\f145;\n$fa-var-power-off: \\f011;\n$fa-var-right-long: \\f30b;\n$fa-var-long-arrow-alt-right: \\f30b;\n$fa-var-flag-usa: \\f74d;\n$fa-var-laptop-file: \\e51d;\n$fa-var-tty: \\f1e4;\n$fa-var-teletype: \\f1e4;\n$fa-var-diagram-next: \\e476;\n$fa-var-person-rifle: \\e54e;\n$fa-var-house-medical-circle-exclamation: \\e512;\n$fa-var-closed-captioning: \\f20a;\n$fa-var-person-hiking: \\f6ec;\n$fa-var-hiking: \\f6ec;\n$fa-var-venus-double: \\f226;\n$fa-var-images: \\f302;\n$fa-var-calculator: \\f1ec;\n$fa-var-people-pulling: \\e535;\n$fa-var-n: \\4e;\n$fa-var-cable-car: \\f7da;\n$fa-var-tram: \\f7da;\n$fa-var-cloud-rain: \\f73d;\n$fa-var-building-circle-xmark: \\e4d4;\n$fa-var-ship: \\f21a;\n$fa-var-arrows-down-to-line: \\e4b8;\n$fa-var-download: \\f019;\n$fa-var-face-grin: \\f580;\n$fa-var-grin: \\f580;\n$fa-var-delete-left: \\f55a;\n$fa-var-backspace: \\f55a;\n$fa-var-eye-dropper: \\f1fb;\n$fa-var-eye-dropper-empty: \\f1fb;\n$fa-var-eyedropper: \\f1fb;\n$fa-var-file-circle-check: \\e5a0;\n$fa-var-forward: \\f04e;\n$fa-var-mobile: \\f3ce;\n$fa-var-mobile-android: \\f3ce;\n$fa-var-mobile-phone: \\f3ce;\n$fa-var-face-meh: \\f11a;\n$fa-var-meh: \\f11a;\n$fa-var-align-center: \\f037;\n$fa-var-book-skull: \\f6b7;\n$fa-var-book-dead: \\f6b7;\n$fa-var-id-card: \\f2c2;\n$fa-var-drivers-license: \\f2c2;\n$fa-var-outdent: \\f03b;\n$fa-var-dedent: \\f03b;\n$fa-var-heart-circle-exclamation: \\e4fe;\n$fa-var-house: \\f015;\n$fa-var-home: \\f015;\n$fa-var-home-alt: \\f015;\n$fa-var-home-lg-alt: \\f015;\n$fa-var-calendar-week: \\f784;\n$fa-var-laptop-medical: \\f812;\n$fa-var-b: \\42;\n$fa-var-file-medical: \\f477;\n$fa-var-dice-one: \\f525;\n$fa-var-kiwi-bird: \\f535;\n$fa-var-arrow-right-arrow-left: \\f0ec;\n$fa-var-exchange: \\f0ec;\n$fa-var-rotate-right: \\f2f9;\n$fa-var-redo-alt: \\f2f9;\n$fa-var-rotate-forward: \\f2f9;\n$fa-var-utensils: \\f2e7;\n$fa-var-cutlery: \\f2e7;\n$fa-var-arrow-up-wide-short: \\f161;\n$fa-var-sort-amount-up: \\f161;\n$fa-var-mill-sign: \\e1ed;\n$fa-var-bowl-rice: \\e2eb;\n$fa-var-skull: \\f54c;\n$fa-var-tower-broadcast: \\f519;\n$fa-var-broadcast-tower: \\f519;\n$fa-var-truck-pickup: \\f63c;\n$fa-var-up-long: \\f30c;\n$fa-var-long-arrow-alt-up: \\f30c;\n$fa-var-stop: \\f04d;\n$fa-var-code-merge: \\f387;\n$fa-var-upload: \\f093;\n$fa-var-hurricane: \\f751;\n$fa-var-mound: \\e52d;\n$fa-var-toilet-portable: \\e583;\n$fa-var-compact-disc: \\f51f;\n$fa-var-file-arrow-down: \\f56d;\n$fa-var-file-download: \\f56d;\n$fa-var-caravan: \\f8ff;\n$fa-var-shield-cat: \\e572;\n$fa-var-bolt: \\f0e7;\n$fa-var-zap: \\f0e7;\n$fa-var-glass-water: \\e4f4;\n$fa-var-oil-well: \\e532;\n$fa-var-vault: \\e2c5;\n$fa-var-mars: \\f222;\n$fa-var-toilet: \\f7d8;\n$fa-var-plane-circle-xmark: \\e557;\n$fa-var-yen-sign: \\f157;\n$fa-var-cny: \\f157;\n$fa-var-jpy: \\f157;\n$fa-var-rmb: \\f157;\n$fa-var-yen: \\f157;\n$fa-var-ruble-sign: \\f158;\n$fa-var-rouble: \\f158;\n$fa-var-rub: \\f158;\n$fa-var-ruble: \\f158;\n$fa-var-sun: \\f185;\n$fa-var-guitar: \\f7a6;\n$fa-var-face-laugh-wink: \\f59c;\n$fa-var-laugh-wink: \\f59c;\n$fa-var-horse-head: \\f7ab;\n$fa-var-bore-hole: \\e4c3;\n$fa-var-industry: \\f275;\n$fa-var-circle-down: \\f358;\n$fa-var-arrow-alt-circle-down: \\f358;\n$fa-var-arrows-turn-to-dots: \\e4c1;\n$fa-var-florin-sign: \\e184;\n$fa-var-arrow-down-short-wide: \\f884;\n$fa-var-sort-amount-desc: \\f884;\n$fa-var-sort-amount-down-alt: \\f884;\n$fa-var-less-than: \\3c;\n$fa-var-angle-down: \\f107;\n$fa-var-car-tunnel: \\e4de;\n$fa-var-head-side-cough: \\e061;\n$fa-var-grip-lines: \\f7a4;\n$fa-var-thumbs-down: \\f165;\n$fa-var-user-lock: \\f502;\n$fa-var-arrow-right-long: \\f178;\n$fa-var-long-arrow-right: \\f178;\n$fa-var-anchor-circle-xmark: \\e4ac;\n$fa-var-ellipsis: \\f141;\n$fa-var-ellipsis-h: \\f141;\n$fa-var-chess-pawn: \\f443;\n$fa-var-kit-medical: \\f479;\n$fa-var-first-aid: \\f479;\n$fa-var-person-through-window: \\e5a9;\n$fa-var-toolbox: \\f552;\n$fa-var-hands-holding-circle: \\e4fb;\n$fa-var-bug: \\f188;\n$fa-var-credit-card: \\f09d;\n$fa-var-credit-card-alt: \\f09d;\n$fa-var-car: \\f1b9;\n$fa-var-automobile: \\f1b9;\n$fa-var-hand-holding-hand: \\e4f7;\n$fa-var-book-open-reader: \\f5da;\n$fa-var-book-reader: \\f5da;\n$fa-var-mountain-sun: \\e52f;\n$fa-var-arrows-left-right-to-line: \\e4ba;\n$fa-var-dice-d20: \\f6cf;\n$fa-var-truck-droplet: \\e58c;\n$fa-var-file-circle-xmark: \\e5a1;\n$fa-var-temperature-arrow-up: \\e040;\n$fa-var-temperature-up: \\e040;\n$fa-var-medal: \\f5a2;\n$fa-var-bed: \\f236;\n$fa-var-square-h: \\f0fd;\n$fa-var-h-square: \\f0fd;\n$fa-var-podcast: \\f2ce;\n$fa-var-temperature-full: \\f2c7;\n$fa-var-temperature-4: \\f2c7;\n$fa-var-thermometer-4: \\f2c7;\n$fa-var-thermometer-full: \\f2c7;\n$fa-var-bell: \\f0f3;\n$fa-var-superscript: \\f12b;\n$fa-var-plug-circle-xmark: \\e560;\n$fa-var-star-of-life: \\f621;\n$fa-var-phone-slash: \\f3dd;\n$fa-var-paint-roller: \\f5aa;\n$fa-var-handshake-angle: \\f4c4;\n$fa-var-hands-helping: \\f4c4;\n$fa-var-location-dot: \\f3c5;\n$fa-var-map-marker-alt: \\f3c5;\n$fa-var-file: \\f15b;\n$fa-var-greater-than: \\3e;\n$fa-var-person-swimming: \\f5c4;\n$fa-var-swimmer: \\f5c4;\n$fa-var-arrow-down: \\f063;\n$fa-var-droplet: \\f043;\n$fa-var-tint: \\f043;\n$fa-var-eraser: \\f12d;\n$fa-var-earth-americas: \\f57d;\n$fa-var-earth: \\f57d;\n$fa-var-earth-america: \\f57d;\n$fa-var-globe-americas: \\f57d;\n$fa-var-person-burst: \\e53b;\n$fa-var-dove: \\f4ba;\n$fa-var-battery-empty: \\f244;\n$fa-var-battery-0: \\f244;\n$fa-var-socks: \\f696;\n$fa-var-inbox: \\f01c;\n$fa-var-section: \\e447;\n$fa-var-gauge-high: \\f625;\n$fa-var-tachometer-alt: \\f625;\n$fa-var-tachometer-alt-fast: \\f625;\n$fa-var-envelope-open-text: \\f658;\n$fa-var-hospital: \\f0f8;\n$fa-var-hospital-alt: \\f0f8;\n$fa-var-hospital-wide: \\f0f8;\n$fa-var-wine-bottle: \\f72f;\n$fa-var-chess-rook: \\f447;\n$fa-var-bars-staggered: \\f550;\n$fa-var-reorder: \\f550;\n$fa-var-stream: \\f550;\n$fa-var-dharmachakra: \\f655;\n$fa-var-hotdog: \\f80f;\n$fa-var-person-walking-with-cane: \\f29d;\n$fa-var-blind: \\f29d;\n$fa-var-drum: \\f569;\n$fa-var-ice-cream: \\f810;\n$fa-var-heart-circle-bolt: \\e4fc;\n$fa-var-fax: \\f1ac;\n$fa-var-paragraph: \\f1dd;\n$fa-var-check-to-slot: \\f772;\n$fa-var-vote-yea: \\f772;\n$fa-var-star-half: \\f089;\n$fa-var-boxes-stacked: \\f468;\n$fa-var-boxes: \\f468;\n$fa-var-boxes-alt: \\f468;\n$fa-var-link: \\f0c1;\n$fa-var-chain: \\f0c1;\n$fa-var-ear-listen: \\f2a2;\n$fa-var-assistive-listening-systems: \\f2a2;\n$fa-var-tree-city: \\e587;\n$fa-var-play: \\f04b;\n$fa-var-font: \\f031;\n$fa-var-table-cells-row-lock: \\e67a;\n$fa-var-rupiah-sign: \\e23d;\n$fa-var-magnifying-glass: \\f002;\n$fa-var-search: \\f002;\n$fa-var-table-tennis-paddle-ball: \\f45d;\n$fa-var-ping-pong-paddle-ball: \\f45d;\n$fa-var-table-tennis: \\f45d;\n$fa-var-person-dots-from-line: \\f470;\n$fa-var-diagnoses: \\f470;\n$fa-var-trash-can-arrow-up: \\f82a;\n$fa-var-trash-restore-alt: \\f82a;\n$fa-var-naira-sign: \\e1f6;\n$fa-var-cart-arrow-down: \\f218;\n$fa-var-walkie-talkie: \\f8ef;\n$fa-var-file-pen: \\f31c;\n$fa-var-file-edit: \\f31c;\n$fa-var-receipt: \\f543;\n$fa-var-square-pen: \\f14b;\n$fa-var-pen-square: \\f14b;\n$fa-var-pencil-square: \\f14b;\n$fa-var-suitcase-rolling: \\f5c1;\n$fa-var-person-circle-exclamation: \\e53f;\n$fa-var-chevron-down: \\f078;\n$fa-var-battery-full: \\f240;\n$fa-var-battery: \\f240;\n$fa-var-battery-5: \\f240;\n$fa-var-skull-crossbones: \\f714;\n$fa-var-code-compare: \\e13a;\n$fa-var-list-ul: \\f0ca;\n$fa-var-list-dots: \\f0ca;\n$fa-var-school-lock: \\e56f;\n$fa-var-tower-cell: \\e585;\n$fa-var-down-long: \\f309;\n$fa-var-long-arrow-alt-down: \\f309;\n$fa-var-ranking-star: \\e561;\n$fa-var-chess-king: \\f43f;\n$fa-var-person-harassing: \\e549;\n$fa-var-brazilian-real-sign: \\e46c;\n$fa-var-landmark-dome: \\f752;\n$fa-var-landmark-alt: \\f752;\n$fa-var-arrow-up: \\f062;\n$fa-var-tv: \\f26c;\n$fa-var-television: \\f26c;\n$fa-var-tv-alt: \\f26c;\n$fa-var-shrimp: \\e448;\n$fa-var-list-check: \\f0ae;\n$fa-var-tasks: \\f0ae;\n$fa-var-jug-detergent: \\e519;\n$fa-var-circle-user: \\f2bd;\n$fa-var-user-circle: \\f2bd;\n$fa-var-user-shield: \\f505;\n$fa-var-wind: \\f72e;\n$fa-var-car-burst: \\f5e1;\n$fa-var-car-crash: \\f5e1;\n$fa-var-y: \\59;\n$fa-var-person-snowboarding: \\f7ce;\n$fa-var-snowboarding: \\f7ce;\n$fa-var-truck-fast: \\f48b;\n$fa-var-shipping-fast: \\f48b;\n$fa-var-fish: \\f578;\n$fa-var-user-graduate: \\f501;\n$fa-var-circle-half-stroke: \\f042;\n$fa-var-adjust: \\f042;\n$fa-var-clapperboard: \\e131;\n$fa-var-circle-radiation: \\f7ba;\n$fa-var-radiation-alt: \\f7ba;\n$fa-var-baseball: \\f433;\n$fa-var-baseball-ball: \\f433;\n$fa-var-jet-fighter-up: \\e518;\n$fa-var-diagram-project: \\f542;\n$fa-var-project-diagram: \\f542;\n$fa-var-copy: \\f0c5;\n$fa-var-volume-xmark: \\f6a9;\n$fa-var-volume-mute: \\f6a9;\n$fa-var-volume-times: \\f6a9;\n$fa-var-hand-sparkles: \\e05d;\n$fa-var-grip: \\f58d;\n$fa-var-grip-horizontal: \\f58d;\n$fa-var-share-from-square: \\f14d;\n$fa-var-share-square: \\f14d;\n$fa-var-child-combatant: \\e4e0;\n$fa-var-child-rifle: \\e4e0;\n$fa-var-gun: \\e19b;\n$fa-var-square-phone: \\f098;\n$fa-var-phone-square: \\f098;\n$fa-var-plus: \\2b;\n$fa-var-add: \\2b;\n$fa-var-expand: \\f065;\n$fa-var-computer: \\e4e5;\n$fa-var-xmark: \\f00d;\n$fa-var-close: \\f00d;\n$fa-var-multiply: \\f00d;\n$fa-var-remove: \\f00d;\n$fa-var-times: \\f00d;\n$fa-var-arrows-up-down-left-right: \\f047;\n$fa-var-arrows: \\f047;\n$fa-var-chalkboard-user: \\f51c;\n$fa-var-chalkboard-teacher: \\f51c;\n$fa-var-peso-sign: \\e222;\n$fa-var-building-shield: \\e4d8;\n$fa-var-baby: \\f77c;\n$fa-var-users-line: \\e592;\n$fa-var-quote-left: \\f10d;\n$fa-var-quote-left-alt: \\f10d;\n$fa-var-tractor: \\f722;\n$fa-var-trash-arrow-up: \\f829;\n$fa-var-trash-restore: \\f829;\n$fa-var-arrow-down-up-lock: \\e4b0;\n$fa-var-lines-leaning: \\e51e;\n$fa-var-ruler-combined: \\f546;\n$fa-var-copyright: \\f1f9;\n$fa-var-equals: \\3d;\n$fa-var-blender: \\f517;\n$fa-var-teeth: \\f62e;\n$fa-var-shekel-sign: \\f20b;\n$fa-var-ils: \\f20b;\n$fa-var-shekel: \\f20b;\n$fa-var-sheqel: \\f20b;\n$fa-var-sheqel-sign: \\f20b;\n$fa-var-map: \\f279;\n$fa-var-rocket: \\f135;\n$fa-var-photo-film: \\f87c;\n$fa-var-photo-video: \\f87c;\n$fa-var-folder-minus: \\f65d;\n$fa-var-hexagon-nodes-bolt: \\e69a;\n$fa-var-store: \\f54e;\n$fa-var-arrow-trend-up: \\e098;\n$fa-var-plug-circle-minus: \\e55e;\n$fa-var-sign-hanging: \\f4d9;\n$fa-var-sign: \\f4d9;\n$fa-var-bezier-curve: \\f55b;\n$fa-var-bell-slash: \\f1f6;\n$fa-var-tablet: \\f3fb;\n$fa-var-tablet-android: \\f3fb;\n$fa-var-school-flag: \\e56e;\n$fa-var-fill: \\f575;\n$fa-var-angle-up: \\f106;\n$fa-var-drumstick-bite: \\f6d7;\n$fa-var-holly-berry: \\f7aa;\n$fa-var-chevron-left: \\f053;\n$fa-var-bacteria: \\e059;\n$fa-var-hand-lizard: \\f258;\n$fa-var-notdef: \\e1fe;\n$fa-var-disease: \\f7fa;\n$fa-var-briefcase-medical: \\f469;\n$fa-var-genderless: \\f22d;\n$fa-var-chevron-right: \\f054;\n$fa-var-retweet: \\f079;\n$fa-var-car-rear: \\f5de;\n$fa-var-car-alt: \\f5de;\n$fa-var-pump-soap: \\e06b;\n$fa-var-video-slash: \\f4e2;\n$fa-var-battery-quarter: \\f243;\n$fa-var-battery-2: \\f243;\n$fa-var-radio: \\f8d7;\n$fa-var-baby-carriage: \\f77d;\n$fa-var-carriage-baby: \\f77d;\n$fa-var-traffic-light: \\f637;\n$fa-var-thermometer: \\f491;\n$fa-var-vr-cardboard: \\f729;\n$fa-var-hand-middle-finger: \\f806;\n$fa-var-percent: \\25;\n$fa-var-percentage: \\25;\n$fa-var-truck-moving: \\f4df;\n$fa-var-glass-water-droplet: \\e4f5;\n$fa-var-display: \\e163;\n$fa-var-face-smile: \\f118;\n$fa-var-smile: \\f118;\n$fa-var-thumbtack: \\f08d;\n$fa-var-thumb-tack: \\f08d;\n$fa-var-trophy: \\f091;\n$fa-var-person-praying: \\f683;\n$fa-var-pray: \\f683;\n$fa-var-hammer: \\f6e3;\n$fa-var-hand-peace: \\f25b;\n$fa-var-rotate: \\f2f1;\n$fa-var-sync-alt: \\f2f1;\n$fa-var-spinner: \\f110;\n$fa-var-robot: \\f544;\n$fa-var-peace: \\f67c;\n$fa-var-gears: \\f085;\n$fa-var-cogs: \\f085;\n$fa-var-warehouse: \\f494;\n$fa-var-arrow-up-right-dots: \\e4b7;\n$fa-var-splotch: \\f5bc;\n$fa-var-face-grin-hearts: \\f584;\n$fa-var-grin-hearts: \\f584;\n$fa-var-dice-four: \\f524;\n$fa-var-sim-card: \\f7c4;\n$fa-var-transgender: \\f225;\n$fa-var-transgender-alt: \\f225;\n$fa-var-mercury: \\f223;\n$fa-var-arrow-turn-down: \\f149;\n$fa-var-level-down: \\f149;\n$fa-var-person-falling-burst: \\e547;\n$fa-var-award: \\f559;\n$fa-var-ticket-simple: \\f3ff;\n$fa-var-ticket-alt: \\f3ff;\n$fa-var-building: \\f1ad;\n$fa-var-angles-left: \\f100;\n$fa-var-angle-double-left: \\f100;\n$fa-var-qrcode: \\f029;\n$fa-var-clock-rotate-left: \\f1da;\n$fa-var-history: \\f1da;\n$fa-var-face-grin-beam-sweat: \\f583;\n$fa-var-grin-beam-sweat: \\f583;\n$fa-var-file-export: \\f56e;\n$fa-var-arrow-right-from-file: \\f56e;\n$fa-var-shield: \\f132;\n$fa-var-shield-blank: \\f132;\n$fa-var-arrow-up-short-wide: \\f885;\n$fa-var-sort-amount-up-alt: \\f885;\n$fa-var-comment-nodes: \\e696;\n$fa-var-house-medical: \\e3b2;\n$fa-var-golf-ball-tee: \\f450;\n$fa-var-golf-ball: \\f450;\n$fa-var-circle-chevron-left: \\f137;\n$fa-var-chevron-circle-left: \\f137;\n$fa-var-house-chimney-window: \\e00d;\n$fa-var-pen-nib: \\f5ad;\n$fa-var-tent-arrow-turn-left: \\e580;\n$fa-var-tents: \\e582;\n$fa-var-wand-magic: \\f0d0;\n$fa-var-magic: \\f0d0;\n$fa-var-dog: \\f6d3;\n$fa-var-carrot: \\f787;\n$fa-var-moon: \\f186;\n$fa-var-wine-glass-empty: \\f5ce;\n$fa-var-wine-glass-alt: \\f5ce;\n$fa-var-cheese: \\f7ef;\n$fa-var-yin-yang: \\f6ad;\n$fa-var-music: \\f001;\n$fa-var-code-commit: \\f386;\n$fa-var-temperature-low: \\f76b;\n$fa-var-person-biking: \\f84a;\n$fa-var-biking: \\f84a;\n$fa-var-broom: \\f51a;\n$fa-var-shield-heart: \\e574;\n$fa-var-gopuram: \\f664;\n$fa-var-earth-oceania: \\e47b;\n$fa-var-globe-oceania: \\e47b;\n$fa-var-square-xmark: \\f2d3;\n$fa-var-times-square: \\f2d3;\n$fa-var-xmark-square: \\f2d3;\n$fa-var-hashtag: \\23;\n$fa-var-up-right-and-down-left-from-center: \\f424;\n$fa-var-expand-alt: \\f424;\n$fa-var-oil-can: \\f613;\n$fa-var-t: \\54;\n$fa-var-hippo: \\f6ed;\n$fa-var-chart-column: \\e0e3;\n$fa-var-infinity: \\f534;\n$fa-var-vial-circle-check: \\e596;\n$fa-var-person-arrow-down-to-line: \\e538;\n$fa-var-voicemail: \\f897;\n$fa-var-fan: \\f863;\n$fa-var-person-walking-luggage: \\e554;\n$fa-var-up-down: \\f338;\n$fa-var-arrows-alt-v: \\f338;\n$fa-var-cloud-moon-rain: \\f73c;\n$fa-var-calendar: \\f133;\n$fa-var-trailer: \\e041;\n$fa-var-bahai: \\f666;\n$fa-var-haykal: \\f666;\n$fa-var-sd-card: \\f7c2;\n$fa-var-dragon: \\f6d5;\n$fa-var-shoe-prints: \\f54b;\n$fa-var-circle-plus: \\f055;\n$fa-var-plus-circle: \\f055;\n$fa-var-face-grin-tongue-wink: \\f58b;\n$fa-var-grin-tongue-wink: \\f58b;\n$fa-var-hand-holding: \\f4bd;\n$fa-var-plug-circle-exclamation: \\e55d;\n$fa-var-link-slash: \\f127;\n$fa-var-chain-broken: \\f127;\n$fa-var-chain-slash: \\f127;\n$fa-var-unlink: \\f127;\n$fa-var-clone: \\f24d;\n$fa-var-person-walking-arrow-loop-left: \\e551;\n$fa-var-arrow-up-z-a: \\f882;\n$fa-var-sort-alpha-up-alt: \\f882;\n$fa-var-fire-flame-curved: \\f7e4;\n$fa-var-fire-alt: \\f7e4;\n$fa-var-tornado: \\f76f;\n$fa-var-file-circle-plus: \\e494;\n$fa-var-book-quran: \\f687;\n$fa-var-quran: \\f687;\n$fa-var-anchor: \\f13d;\n$fa-var-border-all: \\f84c;\n$fa-var-face-angry: \\f556;\n$fa-var-angry: \\f556;\n$fa-var-cookie-bite: \\f564;\n$fa-var-arrow-trend-down: \\e097;\n$fa-var-rss: \\f09e;\n$fa-var-feed: \\f09e;\n$fa-var-draw-polygon: \\f5ee;\n$fa-var-scale-balanced: \\f24e;\n$fa-var-balance-scale: \\f24e;\n$fa-var-gauge-simple-high: \\f62a;\n$fa-var-tachometer: \\f62a;\n$fa-var-tachometer-fast: \\f62a;\n$fa-var-shower: \\f2cc;\n$fa-var-desktop: \\f390;\n$fa-var-desktop-alt: \\f390;\n$fa-var-m: \\4d;\n$fa-var-table-list: \\f00b;\n$fa-var-th-list: \\f00b;\n$fa-var-comment-sms: \\f7cd;\n$fa-var-sms: \\f7cd;\n$fa-var-book: \\f02d;\n$fa-var-user-plus: \\f234;\n$fa-var-check: \\f00c;\n$fa-var-battery-three-quarters: \\f241;\n$fa-var-battery-4: \\f241;\n$fa-var-house-circle-check: \\e509;\n$fa-var-angle-left: \\f104;\n$fa-var-diagram-successor: \\e47a;\n$fa-var-truck-arrow-right: \\e58b;\n$fa-var-arrows-split-up-and-left: \\e4bc;\n$fa-var-hand-fist: \\f6de;\n$fa-var-fist-raised: \\f6de;\n$fa-var-cloud-moon: \\f6c3;\n$fa-var-briefcase: \\f0b1;\n$fa-var-person-falling: \\e546;\n$fa-var-image-portrait: \\f3e0;\n$fa-var-portrait: \\f3e0;\n$fa-var-user-tag: \\f507;\n$fa-var-rug: \\e569;\n$fa-var-earth-europe: \\f7a2;\n$fa-var-globe-europe: \\f7a2;\n$fa-var-cart-flatbed-suitcase: \\f59d;\n$fa-var-luggage-cart: \\f59d;\n$fa-var-rectangle-xmark: \\f410;\n$fa-var-rectangle-times: \\f410;\n$fa-var-times-rectangle: \\f410;\n$fa-var-window-close: \\f410;\n$fa-var-baht-sign: \\e0ac;\n$fa-var-book-open: \\f518;\n$fa-var-book-journal-whills: \\f66a;\n$fa-var-journal-whills: \\f66a;\n$fa-var-handcuffs: \\e4f8;\n$fa-var-triangle-exclamation: \\f071;\n$fa-var-exclamation-triangle: \\f071;\n$fa-var-warning: \\f071;\n$fa-var-database: \\f1c0;\n$fa-var-share: \\f064;\n$fa-var-mail-forward: \\f064;\n$fa-var-bottle-droplet: \\e4c4;\n$fa-var-mask-face: \\e1d7;\n$fa-var-hill-rockslide: \\e508;\n$fa-var-right-left: \\f362;\n$fa-var-exchange-alt: \\f362;\n$fa-var-paper-plane: \\f1d8;\n$fa-var-road-circle-exclamation: \\e565;\n$fa-var-dungeon: \\f6d9;\n$fa-var-align-right: \\f038;\n$fa-var-money-bill-1-wave: \\f53b;\n$fa-var-money-bill-wave-alt: \\f53b;\n$fa-var-life-ring: \\f1cd;\n$fa-var-hands: \\f2a7;\n$fa-var-sign-language: \\f2a7;\n$fa-var-signing: \\f2a7;\n$fa-var-calendar-day: \\f783;\n$fa-var-water-ladder: \\f5c5;\n$fa-var-ladder-water: \\f5c5;\n$fa-var-swimming-pool: \\f5c5;\n$fa-var-arrows-up-down: \\f07d;\n$fa-var-arrows-v: \\f07d;\n$fa-var-face-grimace: \\f57f;\n$fa-var-grimace: \\f57f;\n$fa-var-wheelchair-move: \\e2ce;\n$fa-var-wheelchair-alt: \\e2ce;\n$fa-var-turn-down: \\f3be;\n$fa-var-level-down-alt: \\f3be;\n$fa-var-person-walking-arrow-right: \\e552;\n$fa-var-square-envelope: \\f199;\n$fa-var-envelope-square: \\f199;\n$fa-var-dice: \\f522;\n$fa-var-bowling-ball: \\f436;\n$fa-var-brain: \\f5dc;\n$fa-var-bandage: \\f462;\n$fa-var-band-aid: \\f462;\n$fa-var-calendar-minus: \\f272;\n$fa-var-circle-xmark: \\f057;\n$fa-var-times-circle: \\f057;\n$fa-var-xmark-circle: \\f057;\n$fa-var-gifts: \\f79c;\n$fa-var-hotel: \\f594;\n$fa-var-earth-asia: \\f57e;\n$fa-var-globe-asia: \\f57e;\n$fa-var-id-card-clip: \\f47f;\n$fa-var-id-card-alt: \\f47f;\n$fa-var-magnifying-glass-plus: \\f00e;\n$fa-var-search-plus: \\f00e;\n$fa-var-thumbs-up: \\f164;\n$fa-var-user-clock: \\f4fd;\n$fa-var-hand-dots: \\f461;\n$fa-var-allergies: \\f461;\n$fa-var-file-invoice: \\f570;\n$fa-var-window-minimize: \\f2d1;\n$fa-var-mug-saucer: \\f0f4;\n$fa-var-coffee: \\f0f4;\n$fa-var-brush: \\f55d;\n$fa-var-file-half-dashed: \\e698;\n$fa-var-mask: \\f6fa;\n$fa-var-magnifying-glass-minus: \\f010;\n$fa-var-search-minus: \\f010;\n$fa-var-ruler-vertical: \\f548;\n$fa-var-user-large: \\f406;\n$fa-var-user-alt: \\f406;\n$fa-var-train-tram: \\e5b4;\n$fa-var-user-nurse: \\f82f;\n$fa-var-syringe: \\f48e;\n$fa-var-cloud-sun: \\f6c4;\n$fa-var-stopwatch-20: \\e06f;\n$fa-var-square-full: \\f45c;\n$fa-var-magnet: \\f076;\n$fa-var-jar: \\e516;\n$fa-var-note-sticky: \\f249;\n$fa-var-sticky-note: \\f249;\n$fa-var-bug-slash: \\e490;\n$fa-var-arrow-up-from-water-pump: \\e4b6;\n$fa-var-bone: \\f5d7;\n$fa-var-table-cells-row-unlock: \\e691;\n$fa-var-user-injured: \\f728;\n$fa-var-face-sad-tear: \\f5b4;\n$fa-var-sad-tear: \\f5b4;\n$fa-var-plane: \\f072;\n$fa-var-tent-arrows-down: \\e581;\n$fa-var-exclamation: \\21;\n$fa-var-arrows-spin: \\e4bb;\n$fa-var-print: \\f02f;\n$fa-var-turkish-lira-sign: \\e2bb;\n$fa-var-try: \\e2bb;\n$fa-var-turkish-lira: \\e2bb;\n$fa-var-dollar-sign: \\24;\n$fa-var-dollar: \\24;\n$fa-var-usd: \\24;\n$fa-var-x: \\58;\n$fa-var-magnifying-glass-dollar: \\f688;\n$fa-var-search-dollar: \\f688;\n$fa-var-users-gear: \\f509;\n$fa-var-users-cog: \\f509;\n$fa-var-person-military-pointing: \\e54a;\n$fa-var-building-columns: \\f19c;\n$fa-var-bank: \\f19c;\n$fa-var-institution: \\f19c;\n$fa-var-museum: \\f19c;\n$fa-var-university: \\f19c;\n$fa-var-umbrella: \\f0e9;\n$fa-var-trowel: \\e589;\n$fa-var-d: \\44;\n$fa-var-stapler: \\e5af;\n$fa-var-masks-theater: \\f630;\n$fa-var-theater-masks: \\f630;\n$fa-var-kip-sign: \\e1c4;\n$fa-var-hand-point-left: \\f0a5;\n$fa-var-handshake-simple: \\f4c6;\n$fa-var-handshake-alt: \\f4c6;\n$fa-var-jet-fighter: \\f0fb;\n$fa-var-fighter-jet: \\f0fb;\n$fa-var-square-share-nodes: \\f1e1;\n$fa-var-share-alt-square: \\f1e1;\n$fa-var-barcode: \\f02a;\n$fa-var-plus-minus: \\e43c;\n$fa-var-video: \\f03d;\n$fa-var-video-camera: \\f03d;\n$fa-var-graduation-cap: \\f19d;\n$fa-var-mortar-board: \\f19d;\n$fa-var-hand-holding-medical: \\e05c;\n$fa-var-person-circle-check: \\e53e;\n$fa-var-turn-up: \\f3bf;\n$fa-var-level-up-alt: \\f3bf;\n\n$fa-var-monero: \\f3d0;\n$fa-var-hooli: \\f427;\n$fa-var-yelp: \\f1e9;\n$fa-var-cc-visa: \\f1f0;\n$fa-var-lastfm: \\f202;\n$fa-var-shopware: \\f5b5;\n$fa-var-creative-commons-nc: \\f4e8;\n$fa-var-aws: \\f375;\n$fa-var-redhat: \\f7bc;\n$fa-var-yoast: \\f2b1;\n$fa-var-cloudflare: \\e07d;\n$fa-var-ups: \\f7e0;\n$fa-var-pixiv: \\e640;\n$fa-var-wpexplorer: \\f2de;\n$fa-var-dyalog: \\f399;\n$fa-var-bity: \\f37a;\n$fa-var-stackpath: \\f842;\n$fa-var-buysellads: \\f20d;\n$fa-var-first-order: \\f2b0;\n$fa-var-modx: \\f285;\n$fa-var-guilded: \\e07e;\n$fa-var-vnv: \\f40b;\n$fa-var-square-js: \\f3b9;\n$fa-var-js-square: \\f3b9;\n$fa-var-microsoft: \\f3ca;\n$fa-var-qq: \\f1d6;\n$fa-var-orcid: \\f8d2;\n$fa-var-java: \\f4e4;\n$fa-var-invision: \\f7b0;\n$fa-var-creative-commons-pd-alt: \\f4ed;\n$fa-var-centercode: \\f380;\n$fa-var-glide-g: \\f2a6;\n$fa-var-drupal: \\f1a9;\n$fa-var-jxl: \\e67b;\n$fa-var-dart-lang: \\e693;\n$fa-var-hire-a-helper: \\f3b0;\n$fa-var-creative-commons-by: \\f4e7;\n$fa-var-unity: \\e049;\n$fa-var-whmcs: \\f40d;\n$fa-var-rocketchat: \\f3e8;\n$fa-var-vk: \\f189;\n$fa-var-untappd: \\f405;\n$fa-var-mailchimp: \\f59e;\n$fa-var-css3-alt: \\f38b;\n$fa-var-square-reddit: \\f1a2;\n$fa-var-reddit-square: \\f1a2;\n$fa-var-vimeo-v: \\f27d;\n$fa-var-contao: \\f26d;\n$fa-var-square-font-awesome: \\e5ad;\n$fa-var-deskpro: \\f38f;\n$fa-var-brave: \\e63c;\n$fa-var-sistrix: \\f3ee;\n$fa-var-square-instagram: \\e055;\n$fa-var-instagram-square: \\e055;\n$fa-var-battle-net: \\f835;\n$fa-var-the-red-yeti: \\f69d;\n$fa-var-square-hacker-news: \\f3af;\n$fa-var-hacker-news-square: \\f3af;\n$fa-var-edge: \\f282;\n$fa-var-threads: \\e618;\n$fa-var-napster: \\f3d2;\n$fa-var-square-snapchat: \\f2ad;\n$fa-var-snapchat-square: \\f2ad;\n$fa-var-google-plus-g: \\f0d5;\n$fa-var-artstation: \\f77a;\n$fa-var-markdown: \\f60f;\n$fa-var-sourcetree: \\f7d3;\n$fa-var-google-plus: \\f2b3;\n$fa-var-diaspora: \\f791;\n$fa-var-foursquare: \\f180;\n$fa-var-stack-overflow: \\f16c;\n$fa-var-github-alt: \\f113;\n$fa-var-phoenix-squadron: \\f511;\n$fa-var-pagelines: \\f18c;\n$fa-var-algolia: \\f36c;\n$fa-var-red-river: \\f3e3;\n$fa-var-creative-commons-sa: \\f4ef;\n$fa-var-safari: \\f267;\n$fa-var-google: \\f1a0;\n$fa-var-square-font-awesome-stroke: \\f35c;\n$fa-var-font-awesome-alt: \\f35c;\n$fa-var-atlassian: \\f77b;\n$fa-var-linkedin-in: \\f0e1;\n$fa-var-digital-ocean: \\f391;\n$fa-var-nimblr: \\f5a8;\n$fa-var-chromecast: \\f838;\n$fa-var-evernote: \\f839;\n$fa-var-hacker-news: \\f1d4;\n$fa-var-creative-commons-sampling: \\f4f0;\n$fa-var-adversal: \\f36a;\n$fa-var-creative-commons: \\f25e;\n$fa-var-watchman-monitoring: \\e087;\n$fa-var-fonticons: \\f280;\n$fa-var-weixin: \\f1d7;\n$fa-var-shirtsinbulk: \\f214;\n$fa-var-codepen: \\f1cb;\n$fa-var-git-alt: \\f841;\n$fa-var-lyft: \\f3c3;\n$fa-var-rev: \\f5b2;\n$fa-var-windows: \\f17a;\n$fa-var-wizards-of-the-coast: \\f730;\n$fa-var-square-viadeo: \\f2aa;\n$fa-var-viadeo-square: \\f2aa;\n$fa-var-meetup: \\f2e0;\n$fa-var-centos: \\f789;\n$fa-var-adn: \\f170;\n$fa-var-cloudsmith: \\f384;\n$fa-var-opensuse: \\e62b;\n$fa-var-pied-piper-alt: \\f1a8;\n$fa-var-square-dribbble: \\f397;\n$fa-var-dribbble-square: \\f397;\n$fa-var-codiepie: \\f284;\n$fa-var-node: \\f419;\n$fa-var-mix: \\f3cb;\n$fa-var-steam: \\f1b6;\n$fa-var-cc-apple-pay: \\f416;\n$fa-var-scribd: \\f28a;\n$fa-var-debian: \\e60b;\n$fa-var-openid: \\f19b;\n$fa-var-instalod: \\e081;\n$fa-var-files-pinwheel: \\e69f;\n$fa-var-expeditedssl: \\f23e;\n$fa-var-sellcast: \\f2da;\n$fa-var-square-twitter: \\f081;\n$fa-var-twitter-square: \\f081;\n$fa-var-r-project: \\f4f7;\n$fa-var-delicious: \\f1a5;\n$fa-var-freebsd: \\f3a4;\n$fa-var-vuejs: \\f41f;\n$fa-var-accusoft: \\f369;\n$fa-var-ioxhost: \\f208;\n$fa-var-fonticons-fi: \\f3a2;\n$fa-var-app-store: \\f36f;\n$fa-var-cc-mastercard: \\f1f1;\n$fa-var-itunes-note: \\f3b5;\n$fa-var-golang: \\e40f;\n$fa-var-kickstarter: \\f3bb;\n$fa-var-square-kickstarter: \\f3bb;\n$fa-var-grav: \\f2d6;\n$fa-var-weibo: \\f18a;\n$fa-var-uncharted: \\e084;\n$fa-var-firstdraft: \\f3a1;\n$fa-var-square-youtube: \\f431;\n$fa-var-youtube-square: \\f431;\n$fa-var-wikipedia-w: \\f266;\n$fa-var-wpressr: \\f3e4;\n$fa-var-rendact: \\f3e4;\n$fa-var-angellist: \\f209;\n$fa-var-galactic-republic: \\f50c;\n$fa-var-nfc-directional: \\e530;\n$fa-var-skype: \\f17e;\n$fa-var-joget: \\f3b7;\n$fa-var-fedora: \\f798;\n$fa-var-stripe-s: \\f42a;\n$fa-var-meta: \\e49b;\n$fa-var-laravel: \\f3bd;\n$fa-var-hotjar: \\f3b1;\n$fa-var-bluetooth-b: \\f294;\n$fa-var-square-letterboxd: \\e62e;\n$fa-var-sticker-mule: \\f3f7;\n$fa-var-creative-commons-zero: \\f4f3;\n$fa-var-hips: \\f452;\n$fa-var-css: \\e6a2;\n$fa-var-behance: \\f1b4;\n$fa-var-reddit: \\f1a1;\n$fa-var-discord: \\f392;\n$fa-var-chrome: \\f268;\n$fa-var-app-store-ios: \\f370;\n$fa-var-cc-discover: \\f1f2;\n$fa-var-wpbeginner: \\f297;\n$fa-var-confluence: \\f78d;\n$fa-var-shoelace: \\e60c;\n$fa-var-mdb: \\f8ca;\n$fa-var-dochub: \\f394;\n$fa-var-accessible-icon: \\f368;\n$fa-var-ebay: \\f4f4;\n$fa-var-amazon: \\f270;\n$fa-var-unsplash: \\e07c;\n$fa-var-yarn: \\f7e3;\n$fa-var-square-steam: \\f1b7;\n$fa-var-steam-square: \\f1b7;\n$fa-var-500px: \\f26e;\n$fa-var-square-vimeo: \\f194;\n$fa-var-vimeo-square: \\f194;\n$fa-var-asymmetrik: \\f372;\n$fa-var-font-awesome: \\f2b4;\n$fa-var-font-awesome-flag: \\f2b4;\n$fa-var-font-awesome-logo-full: \\f2b4;\n$fa-var-gratipay: \\f184;\n$fa-var-apple: \\f179;\n$fa-var-hive: \\e07f;\n$fa-var-gitkraken: \\f3a6;\n$fa-var-keybase: \\f4f5;\n$fa-var-apple-pay: \\f415;\n$fa-var-padlet: \\e4a0;\n$fa-var-amazon-pay: \\f42c;\n$fa-var-square-github: \\f092;\n$fa-var-github-square: \\f092;\n$fa-var-stumbleupon: \\f1a4;\n$fa-var-fedex: \\f797;\n$fa-var-phoenix-framework: \\f3dc;\n$fa-var-shopify: \\e057;\n$fa-var-neos: \\f612;\n$fa-var-square-threads: \\e619;\n$fa-var-hackerrank: \\f5f7;\n$fa-var-researchgate: \\f4f8;\n$fa-var-swift: \\f8e1;\n$fa-var-angular: \\f420;\n$fa-var-speakap: \\f3f3;\n$fa-var-angrycreative: \\f36e;\n$fa-var-y-combinator: \\f23b;\n$fa-var-empire: \\f1d1;\n$fa-var-envira: \\f299;\n$fa-var-google-scholar: \\e63b;\n$fa-var-square-gitlab: \\e5ae;\n$fa-var-gitlab-square: \\e5ae;\n$fa-var-studiovinari: \\f3f8;\n$fa-var-pied-piper: \\f2ae;\n$fa-var-wordpress: \\f19a;\n$fa-var-product-hunt: \\f288;\n$fa-var-firefox: \\f269;\n$fa-var-linode: \\f2b8;\n$fa-var-goodreads: \\f3a8;\n$fa-var-square-odnoklassniki: \\f264;\n$fa-var-odnoklassniki-square: \\f264;\n$fa-var-jsfiddle: \\f1cc;\n$fa-var-sith: \\f512;\n$fa-var-themeisle: \\f2b2;\n$fa-var-page4: \\f3d7;\n$fa-var-hashnode: \\e499;\n$fa-var-react: \\f41b;\n$fa-var-cc-paypal: \\f1f4;\n$fa-var-squarespace: \\f5be;\n$fa-var-cc-stripe: \\f1f5;\n$fa-var-creative-commons-share: \\f4f2;\n$fa-var-bitcoin: \\f379;\n$fa-var-keycdn: \\f3ba;\n$fa-var-opera: \\f26a;\n$fa-var-itch-io: \\f83a;\n$fa-var-umbraco: \\f8e8;\n$fa-var-galactic-senate: \\f50d;\n$fa-var-ubuntu: \\f7df;\n$fa-var-draft2digital: \\f396;\n$fa-var-stripe: \\f429;\n$fa-var-houzz: \\f27c;\n$fa-var-gg: \\f260;\n$fa-var-dhl: \\f790;\n$fa-var-square-pinterest: \\f0d3;\n$fa-var-pinterest-square: \\f0d3;\n$fa-var-xing: \\f168;\n$fa-var-blackberry: \\f37b;\n$fa-var-creative-commons-pd: \\f4ec;\n$fa-var-playstation: \\f3df;\n$fa-var-quinscape: \\f459;\n$fa-var-less: \\f41d;\n$fa-var-blogger-b: \\f37d;\n$fa-var-opencart: \\f23d;\n$fa-var-vine: \\f1ca;\n$fa-var-signal-messenger: \\e663;\n$fa-var-paypal: \\f1ed;\n$fa-var-gitlab: \\f296;\n$fa-var-typo3: \\f42b;\n$fa-var-reddit-alien: \\f281;\n$fa-var-yahoo: \\f19e;\n$fa-var-dailymotion: \\e052;\n$fa-var-affiliatetheme: \\f36b;\n$fa-var-pied-piper-pp: \\f1a7;\n$fa-var-bootstrap: \\f836;\n$fa-var-odnoklassniki: \\f263;\n$fa-var-nfc-symbol: \\e531;\n$fa-var-mintbit: \\e62f;\n$fa-var-ethereum: \\f42e;\n$fa-var-speaker-deck: \\f83c;\n$fa-var-creative-commons-nc-eu: \\f4e9;\n$fa-var-patreon: \\f3d9;\n$fa-var-avianex: \\f374;\n$fa-var-ello: \\f5f1;\n$fa-var-gofore: \\f3a7;\n$fa-var-bimobject: \\f378;\n$fa-var-brave-reverse: \\e63d;\n$fa-var-facebook-f: \\f39e;\n$fa-var-square-google-plus: \\f0d4;\n$fa-var-google-plus-square: \\f0d4;\n$fa-var-web-awesome: \\e682;\n$fa-var-mandalorian: \\f50f;\n$fa-var-first-order-alt: \\f50a;\n$fa-var-osi: \\f41a;\n$fa-var-google-wallet: \\f1ee;\n$fa-var-d-and-d-beyond: \\f6ca;\n$fa-var-periscope: \\f3da;\n$fa-var-fulcrum: \\f50b;\n$fa-var-cloudscale: \\f383;\n$fa-var-forumbee: \\f211;\n$fa-var-mizuni: \\f3cc;\n$fa-var-schlix: \\f3ea;\n$fa-var-square-xing: \\f169;\n$fa-var-xing-square: \\f169;\n$fa-var-bandcamp: \\f2d5;\n$fa-var-wpforms: \\f298;\n$fa-var-cloudversify: \\f385;\n$fa-var-usps: \\f7e1;\n$fa-var-megaport: \\f5a3;\n$fa-var-magento: \\f3c4;\n$fa-var-spotify: \\f1bc;\n$fa-var-optin-monster: \\f23c;\n$fa-var-fly: \\f417;\n$fa-var-square-bluesky: \\e6a3;\n$fa-var-aviato: \\f421;\n$fa-var-itunes: \\f3b4;\n$fa-var-cuttlefish: \\f38c;\n$fa-var-blogger: \\f37c;\n$fa-var-flickr: \\f16e;\n$fa-var-viber: \\f409;\n$fa-var-soundcloud: \\f1be;\n$fa-var-digg: \\f1a6;\n$fa-var-tencent-weibo: \\f1d5;\n$fa-var-letterboxd: \\e62d;\n$fa-var-symfony: \\f83d;\n$fa-var-maxcdn: \\f136;\n$fa-var-etsy: \\f2d7;\n$fa-var-facebook-messenger: \\f39f;\n$fa-var-audible: \\f373;\n$fa-var-think-peaks: \\f731;\n$fa-var-bilibili: \\e3d9;\n$fa-var-erlang: \\f39d;\n$fa-var-x-twitter: \\e61b;\n$fa-var-cotton-bureau: \\f89e;\n$fa-var-dashcube: \\f210;\n$fa-var-42-group: \\e080;\n$fa-var-innosoft: \\e080;\n$fa-var-stack-exchange: \\f18d;\n$fa-var-elementor: \\f430;\n$fa-var-square-pied-piper: \\e01e;\n$fa-var-pied-piper-square: \\e01e;\n$fa-var-creative-commons-nd: \\f4eb;\n$fa-var-palfed: \\f3d8;\n$fa-var-superpowers: \\f2dd;\n$fa-var-resolving: \\f3e7;\n$fa-var-xbox: \\f412;\n$fa-var-square-web-awesome-stroke: \\e684;\n$fa-var-searchengin: \\f3eb;\n$fa-var-tiktok: \\e07b;\n$fa-var-square-facebook: \\f082;\n$fa-var-facebook-square: \\f082;\n$fa-var-renren: \\f18b;\n$fa-var-linux: \\f17c;\n$fa-var-glide: \\f2a5;\n$fa-var-linkedin: \\f08c;\n$fa-var-hubspot: \\f3b2;\n$fa-var-deploydog: \\f38e;\n$fa-var-twitch: \\f1e8;\n$fa-var-flutter: \\e694;\n$fa-var-ravelry: \\f2d9;\n$fa-var-mixer: \\e056;\n$fa-var-square-lastfm: \\f203;\n$fa-var-lastfm-square: \\f203;\n$fa-var-vimeo: \\f40a;\n$fa-var-mendeley: \\f7b3;\n$fa-var-uniregistry: \\f404;\n$fa-var-figma: \\f799;\n$fa-var-creative-commons-remix: \\f4ee;\n$fa-var-cc-amazon-pay: \\f42d;\n$fa-var-dropbox: \\f16b;\n$fa-var-instagram: \\f16d;\n$fa-var-cmplid: \\e360;\n$fa-var-upwork: \\e641;\n$fa-var-facebook: \\f09a;\n$fa-var-gripfire: \\f3ac;\n$fa-var-jedi-order: \\f50e;\n$fa-var-uikit: \\f403;\n$fa-var-fort-awesome-alt: \\f3a3;\n$fa-var-phabricator: \\f3db;\n$fa-var-ussunnah: \\f407;\n$fa-var-earlybirds: \\f39a;\n$fa-var-trade-federation: \\f513;\n$fa-var-autoprefixer: \\f41c;\n$fa-var-whatsapp: \\f232;\n$fa-var-square-upwork: \\e67c;\n$fa-var-slideshare: \\f1e7;\n$fa-var-google-play: \\f3ab;\n$fa-var-viadeo: \\f2a9;\n$fa-var-line: \\f3c0;\n$fa-var-google-drive: \\f3aa;\n$fa-var-servicestack: \\f3ec;\n$fa-var-simplybuilt: \\f215;\n$fa-var-bitbucket: \\f171;\n$fa-var-imdb: \\f2d8;\n$fa-var-deezer: \\e077;\n$fa-var-raspberry-pi: \\f7bb;\n$fa-var-jira: \\f7b1;\n$fa-var-docker: \\f395;\n$fa-var-screenpal: \\e570;\n$fa-var-bluetooth: \\f293;\n$fa-var-gitter: \\f426;\n$fa-var-d-and-d: \\f38d;\n$fa-var-microblog: \\e01a;\n$fa-var-cc-diners-club: \\f24c;\n$fa-var-gg-circle: \\f261;\n$fa-var-pied-piper-hat: \\f4e5;\n$fa-var-kickstarter-k: \\f3bc;\n$fa-var-yandex: \\f413;\n$fa-var-readme: \\f4d5;\n$fa-var-html5: \\f13b;\n$fa-var-sellsy: \\f213;\n$fa-var-square-web-awesome: \\e683;\n$fa-var-sass: \\f41e;\n$fa-var-wirsindhandwerk: \\e2d0;\n$fa-var-wsh: \\e2d0;\n$fa-var-buromobelexperte: \\f37f;\n$fa-var-salesforce: \\f83b;\n$fa-var-octopus-deploy: \\e082;\n$fa-var-medapps: \\f3c6;\n$fa-var-ns8: \\f3d5;\n$fa-var-pinterest-p: \\f231;\n$fa-var-apper: \\f371;\n$fa-var-fort-awesome: \\f286;\n$fa-var-waze: \\f83f;\n$fa-var-bluesky: \\e671;\n$fa-var-cc-jcb: \\f24b;\n$fa-var-snapchat: \\f2ab;\n$fa-var-snapchat-ghost: \\f2ab;\n$fa-var-fantasy-flight-games: \\f6dc;\n$fa-var-rust: \\e07a;\n$fa-var-wix: \\f5cf;\n$fa-var-square-behance: \\f1b5;\n$fa-var-behance-square: \\f1b5;\n$fa-var-supple: \\f3f9;\n$fa-var-webflow: \\e65c;\n$fa-var-rebel: \\f1d0;\n$fa-var-css3: \\f13c;\n$fa-var-staylinked: \\f3f5;\n$fa-var-kaggle: \\f5fa;\n$fa-var-space-awesome: \\e5ac;\n$fa-var-deviantart: \\f1bd;\n$fa-var-cpanel: \\f388;\n$fa-var-goodreads-g: \\f3a9;\n$fa-var-square-git: \\f1d2;\n$fa-var-git-square: \\f1d2;\n$fa-var-square-tumblr: \\f174;\n$fa-var-tumblr-square: \\f174;\n$fa-var-trello: \\f181;\n$fa-var-creative-commons-nc-jp: \\f4ea;\n$fa-var-get-pocket: \\f265;\n$fa-var-perbyte: \\e083;\n$fa-var-grunt: \\f3ad;\n$fa-var-weebly: \\f5cc;\n$fa-var-connectdevelop: \\f20e;\n$fa-var-leanpub: \\f212;\n$fa-var-black-tie: \\f27e;\n$fa-var-themeco: \\f5c6;\n$fa-var-python: \\f3e2;\n$fa-var-android: \\f17b;\n$fa-var-bots: \\e340;\n$fa-var-free-code-camp: \\f2c5;\n$fa-var-hornbill: \\f592;\n$fa-var-js: \\f3b8;\n$fa-var-ideal: \\e013;\n$fa-var-git: \\f1d3;\n$fa-var-dev: \\f6cc;\n$fa-var-sketch: \\f7c6;\n$fa-var-yandex-international: \\f414;\n$fa-var-cc-amex: \\f1f3;\n$fa-var-uber: \\f402;\n$fa-var-github: \\f09b;\n$fa-var-php: \\f457;\n$fa-var-alipay: \\f642;\n$fa-var-youtube: \\f167;\n$fa-var-skyatlas: \\f216;\n$fa-var-firefox-browser: \\e007;\n$fa-var-replyd: \\f3e6;\n$fa-var-suse: \\f7d6;\n$fa-var-jenkins: \\f3b6;\n$fa-var-twitter: \\f099;\n$fa-var-rockrms: \\f3e9;\n$fa-var-pinterest: \\f0d2;\n$fa-var-buffer: \\f837;\n$fa-var-npm: \\f3d4;\n$fa-var-yammer: \\f840;\n$fa-var-btc: \\f15a;\n$fa-var-dribbble: \\f17d;\n$fa-var-stumbleupon-circle: \\f1a3;\n$fa-var-internet-explorer: \\f26b;\n$fa-var-stubber: \\e5c7;\n$fa-var-telegram: \\f2c6;\n$fa-var-telegram-plane: \\f2c6;\n$fa-var-old-republic: \\f510;\n$fa-var-odysee: \\e5c6;\n$fa-var-square-whatsapp: \\f40c;\n$fa-var-whatsapp-square: \\f40c;\n$fa-var-node-js: \\f3d3;\n$fa-var-edge-legacy: \\e078;\n$fa-var-slack: \\f198;\n$fa-var-slack-hash: \\f198;\n$fa-var-medrt: \\f3c8;\n$fa-var-usb: \\f287;\n$fa-var-tumblr: \\f173;\n$fa-var-vaadin: \\f408;\n$fa-var-quora: \\f2c4;\n$fa-var-square-x-twitter: \\e61a;\n$fa-var-reacteurope: \\f75d;\n$fa-var-medium: \\f23a;\n$fa-var-medium-m: \\f23a;\n$fa-var-amilia: \\f36d;\n$fa-var-mixcloud: \\f289;\n$fa-var-flipboard: \\f44d;\n$fa-var-viacoin: \\f237;\n$fa-var-critical-role: \\f6c9;\n$fa-var-sitrox: \\e44a;\n$fa-var-discourse: \\f393;\n$fa-var-joomla: \\f1aa;\n$fa-var-mastodon: \\f4f6;\n$fa-var-airbnb: \\f834;\n$fa-var-wolf-pack-battalion: \\f514;\n$fa-var-buy-n-large: \\f8a6;\n$fa-var-gulp: \\f3ae;\n$fa-var-creative-commons-sampling-plus: \\f4f1;\n$fa-var-strava: \\f428;\n$fa-var-ember: \\f423;\n$fa-var-canadian-maple-leaf: \\f785;\n$fa-var-teamspeak: \\f4f9;\n$fa-var-pushed: \\f3e1;\n$fa-var-wordpress-simple: \\f411;\n$fa-var-nutritionix: \\f3d6;\n$fa-var-wodu: \\e088;\n$fa-var-google-pay: \\e079;\n$fa-var-intercom: \\f7af;\n$fa-var-zhihu: \\f63f;\n$fa-var-korvue: \\f42f;\n$fa-var-pix: \\e43a;\n$fa-var-steam-symbol: \\f3f6;\n\n$fa-icons: (\n \"0\": $fa-var-0,\n \"1\": $fa-var-1,\n \"2\": $fa-var-2,\n \"3\": $fa-var-3,\n \"4\": $fa-var-4,\n \"5\": $fa-var-5,\n \"6\": $fa-var-6,\n \"7\": $fa-var-7,\n \"8\": $fa-var-8,\n \"9\": $fa-var-9,\n \"fill-drip\": $fa-var-fill-drip,\n \"arrows-to-circle\": $fa-var-arrows-to-circle,\n \"circle-chevron-right\": $fa-var-circle-chevron-right,\n \"chevron-circle-right\": $fa-var-chevron-circle-right,\n \"at\": $fa-var-at,\n \"trash-can\": $fa-var-trash-can,\n \"trash-alt\": $fa-var-trash-alt,\n \"text-height\": $fa-var-text-height,\n \"user-xmark\": $fa-var-user-xmark,\n \"user-times\": $fa-var-user-times,\n \"stethoscope\": $fa-var-stethoscope,\n \"message\": $fa-var-message,\n \"comment-alt\": $fa-var-comment-alt,\n \"info\": $fa-var-info,\n \"down-left-and-up-right-to-center\": $fa-var-down-left-and-up-right-to-center,\n \"compress-alt\": $fa-var-compress-alt,\n \"explosion\": $fa-var-explosion,\n \"file-lines\": $fa-var-file-lines,\n \"file-alt\": $fa-var-file-alt,\n \"file-text\": $fa-var-file-text,\n \"wave-square\": $fa-var-wave-square,\n \"ring\": $fa-var-ring,\n \"building-un\": $fa-var-building-un,\n \"dice-three\": $fa-var-dice-three,\n \"calendar-days\": $fa-var-calendar-days,\n \"calendar-alt\": $fa-var-calendar-alt,\n \"anchor-circle-check\": $fa-var-anchor-circle-check,\n \"building-circle-arrow-right\": $fa-var-building-circle-arrow-right,\n \"volleyball\": $fa-var-volleyball,\n \"volleyball-ball\": $fa-var-volleyball-ball,\n \"arrows-up-to-line\": $fa-var-arrows-up-to-line,\n \"sort-down\": $fa-var-sort-down,\n \"sort-desc\": $fa-var-sort-desc,\n \"circle-minus\": $fa-var-circle-minus,\n \"minus-circle\": $fa-var-minus-circle,\n \"door-open\": $fa-var-door-open,\n \"right-from-bracket\": $fa-var-right-from-bracket,\n \"sign-out-alt\": $fa-var-sign-out-alt,\n \"atom\": $fa-var-atom,\n \"soap\": $fa-var-soap,\n \"icons\": $fa-var-icons,\n \"heart-music-camera-bolt\": $fa-var-heart-music-camera-bolt,\n \"microphone-lines-slash\": $fa-var-microphone-lines-slash,\n \"microphone-alt-slash\": $fa-var-microphone-alt-slash,\n \"bridge-circle-check\": $fa-var-bridge-circle-check,\n \"pump-medical\": $fa-var-pump-medical,\n \"fingerprint\": $fa-var-fingerprint,\n \"hand-point-right\": $fa-var-hand-point-right,\n \"magnifying-glass-location\": $fa-var-magnifying-glass-location,\n \"search-location\": $fa-var-search-location,\n \"forward-step\": $fa-var-forward-step,\n \"step-forward\": $fa-var-step-forward,\n \"face-smile-beam\": $fa-var-face-smile-beam,\n \"smile-beam\": $fa-var-smile-beam,\n \"flag-checkered\": $fa-var-flag-checkered,\n \"football\": $fa-var-football,\n \"football-ball\": $fa-var-football-ball,\n \"school-circle-exclamation\": $fa-var-school-circle-exclamation,\n \"crop\": $fa-var-crop,\n \"angles-down\": $fa-var-angles-down,\n \"angle-double-down\": $fa-var-angle-double-down,\n \"users-rectangle\": $fa-var-users-rectangle,\n \"people-roof\": $fa-var-people-roof,\n \"people-line\": $fa-var-people-line,\n \"beer-mug-empty\": $fa-var-beer-mug-empty,\n \"beer\": $fa-var-beer,\n \"diagram-predecessor\": $fa-var-diagram-predecessor,\n \"arrow-up-long\": $fa-var-arrow-up-long,\n \"long-arrow-up\": $fa-var-long-arrow-up,\n \"fire-flame-simple\": $fa-var-fire-flame-simple,\n \"burn\": $fa-var-burn,\n \"person\": $fa-var-person,\n \"male\": $fa-var-male,\n \"laptop\": $fa-var-laptop,\n \"file-csv\": $fa-var-file-csv,\n \"menorah\": $fa-var-menorah,\n \"truck-plane\": $fa-var-truck-plane,\n \"record-vinyl\": $fa-var-record-vinyl,\n \"face-grin-stars\": $fa-var-face-grin-stars,\n \"grin-stars\": $fa-var-grin-stars,\n \"bong\": $fa-var-bong,\n \"spaghetti-monster-flying\": $fa-var-spaghetti-monster-flying,\n \"pastafarianism\": $fa-var-pastafarianism,\n \"arrow-down-up-across-line\": $fa-var-arrow-down-up-across-line,\n \"spoon\": $fa-var-spoon,\n \"utensil-spoon\": $fa-var-utensil-spoon,\n \"jar-wheat\": $fa-var-jar-wheat,\n \"envelopes-bulk\": $fa-var-envelopes-bulk,\n \"mail-bulk\": $fa-var-mail-bulk,\n \"file-circle-exclamation\": $fa-var-file-circle-exclamation,\n \"circle-h\": $fa-var-circle-h,\n \"hospital-symbol\": $fa-var-hospital-symbol,\n \"pager\": $fa-var-pager,\n \"address-book\": $fa-var-address-book,\n \"contact-book\": $fa-var-contact-book,\n \"strikethrough\": $fa-var-strikethrough,\n \"k\": $fa-var-k,\n \"landmark-flag\": $fa-var-landmark-flag,\n \"pencil\": $fa-var-pencil,\n \"pencil-alt\": $fa-var-pencil-alt,\n \"backward\": $fa-var-backward,\n \"caret-right\": $fa-var-caret-right,\n \"comments\": $fa-var-comments,\n \"paste\": $fa-var-paste,\n \"file-clipboard\": $fa-var-file-clipboard,\n \"code-pull-request\": $fa-var-code-pull-request,\n \"clipboard-list\": $fa-var-clipboard-list,\n \"truck-ramp-box\": $fa-var-truck-ramp-box,\n \"truck-loading\": $fa-var-truck-loading,\n \"user-check\": $fa-var-user-check,\n \"vial-virus\": $fa-var-vial-virus,\n \"sheet-plastic\": $fa-var-sheet-plastic,\n \"blog\": $fa-var-blog,\n \"user-ninja\": $fa-var-user-ninja,\n \"person-arrow-up-from-line\": $fa-var-person-arrow-up-from-line,\n \"scroll-torah\": $fa-var-scroll-torah,\n \"torah\": $fa-var-torah,\n \"broom-ball\": $fa-var-broom-ball,\n \"quidditch\": $fa-var-quidditch,\n \"quidditch-broom-ball\": $fa-var-quidditch-broom-ball,\n \"toggle-off\": $fa-var-toggle-off,\n \"box-archive\": $fa-var-box-archive,\n \"archive\": $fa-var-archive,\n \"person-drowning\": $fa-var-person-drowning,\n \"arrow-down-9-1\": $fa-var-arrow-down-9-1,\n \"sort-numeric-desc\": $fa-var-sort-numeric-desc,\n \"sort-numeric-down-alt\": $fa-var-sort-numeric-down-alt,\n \"face-grin-tongue-squint\": $fa-var-face-grin-tongue-squint,\n \"grin-tongue-squint\": $fa-var-grin-tongue-squint,\n \"spray-can\": $fa-var-spray-can,\n \"truck-monster\": $fa-var-truck-monster,\n \"w\": $fa-var-w,\n \"earth-africa\": $fa-var-earth-africa,\n \"globe-africa\": $fa-var-globe-africa,\n \"rainbow\": $fa-var-rainbow,\n \"circle-notch\": $fa-var-circle-notch,\n \"tablet-screen-button\": $fa-var-tablet-screen-button,\n \"tablet-alt\": $fa-var-tablet-alt,\n \"paw\": $fa-var-paw,\n \"cloud\": $fa-var-cloud,\n \"trowel-bricks\": $fa-var-trowel-bricks,\n \"face-flushed\": $fa-var-face-flushed,\n \"flushed\": $fa-var-flushed,\n \"hospital-user\": $fa-var-hospital-user,\n \"tent-arrow-left-right\": $fa-var-tent-arrow-left-right,\n \"gavel\": $fa-var-gavel,\n \"legal\": $fa-var-legal,\n \"binoculars\": $fa-var-binoculars,\n \"microphone-slash\": $fa-var-microphone-slash,\n \"box-tissue\": $fa-var-box-tissue,\n \"motorcycle\": $fa-var-motorcycle,\n \"bell-concierge\": $fa-var-bell-concierge,\n \"concierge-bell\": $fa-var-concierge-bell,\n \"pen-ruler\": $fa-var-pen-ruler,\n \"pencil-ruler\": $fa-var-pencil-ruler,\n \"people-arrows\": $fa-var-people-arrows,\n \"people-arrows-left-right\": $fa-var-people-arrows-left-right,\n \"mars-and-venus-burst\": $fa-var-mars-and-venus-burst,\n \"square-caret-right\": $fa-var-square-caret-right,\n \"caret-square-right\": $fa-var-caret-square-right,\n \"scissors\": $fa-var-scissors,\n \"cut\": $fa-var-cut,\n \"sun-plant-wilt\": $fa-var-sun-plant-wilt,\n \"toilets-portable\": $fa-var-toilets-portable,\n \"hockey-puck\": $fa-var-hockey-puck,\n \"table\": $fa-var-table,\n \"magnifying-glass-arrow-right\": $fa-var-magnifying-glass-arrow-right,\n \"tachograph-digital\": $fa-var-tachograph-digital,\n \"digital-tachograph\": $fa-var-digital-tachograph,\n \"users-slash\": $fa-var-users-slash,\n \"clover\": $fa-var-clover,\n \"reply\": $fa-var-reply,\n \"mail-reply\": $fa-var-mail-reply,\n \"star-and-crescent\": $fa-var-star-and-crescent,\n \"house-fire\": $fa-var-house-fire,\n \"square-minus\": $fa-var-square-minus,\n \"minus-square\": $fa-var-minus-square,\n \"helicopter\": $fa-var-helicopter,\n \"compass\": $fa-var-compass,\n \"square-caret-down\": $fa-var-square-caret-down,\n \"caret-square-down\": $fa-var-caret-square-down,\n \"file-circle-question\": $fa-var-file-circle-question,\n \"laptop-code\": $fa-var-laptop-code,\n \"swatchbook\": $fa-var-swatchbook,\n \"prescription-bottle\": $fa-var-prescription-bottle,\n \"bars\": $fa-var-bars,\n \"navicon\": $fa-var-navicon,\n \"people-group\": $fa-var-people-group,\n \"hourglass-end\": $fa-var-hourglass-end,\n \"hourglass-3\": $fa-var-hourglass-3,\n \"heart-crack\": $fa-var-heart-crack,\n \"heart-broken\": $fa-var-heart-broken,\n \"square-up-right\": $fa-var-square-up-right,\n \"external-link-square-alt\": $fa-var-external-link-square-alt,\n \"face-kiss-beam\": $fa-var-face-kiss-beam,\n \"kiss-beam\": $fa-var-kiss-beam,\n \"film\": $fa-var-film,\n \"ruler-horizontal\": $fa-var-ruler-horizontal,\n \"people-robbery\": $fa-var-people-robbery,\n \"lightbulb\": $fa-var-lightbulb,\n \"caret-left\": $fa-var-caret-left,\n \"circle-exclamation\": $fa-var-circle-exclamation,\n \"exclamation-circle\": $fa-var-exclamation-circle,\n \"school-circle-xmark\": $fa-var-school-circle-xmark,\n \"arrow-right-from-bracket\": $fa-var-arrow-right-from-bracket,\n \"sign-out\": $fa-var-sign-out,\n \"circle-chevron-down\": $fa-var-circle-chevron-down,\n \"chevron-circle-down\": $fa-var-chevron-circle-down,\n \"unlock-keyhole\": $fa-var-unlock-keyhole,\n \"unlock-alt\": $fa-var-unlock-alt,\n \"cloud-showers-heavy\": $fa-var-cloud-showers-heavy,\n \"headphones-simple\": $fa-var-headphones-simple,\n \"headphones-alt\": $fa-var-headphones-alt,\n \"sitemap\": $fa-var-sitemap,\n \"circle-dollar-to-slot\": $fa-var-circle-dollar-to-slot,\n \"donate\": $fa-var-donate,\n \"memory\": $fa-var-memory,\n \"road-spikes\": $fa-var-road-spikes,\n \"fire-burner\": $fa-var-fire-burner,\n \"flag\": $fa-var-flag,\n \"hanukiah\": $fa-var-hanukiah,\n \"feather\": $fa-var-feather,\n \"volume-low\": $fa-var-volume-low,\n \"volume-down\": $fa-var-volume-down,\n \"comment-slash\": $fa-var-comment-slash,\n \"cloud-sun-rain\": $fa-var-cloud-sun-rain,\n \"compress\": $fa-var-compress,\n \"wheat-awn\": $fa-var-wheat-awn,\n \"wheat-alt\": $fa-var-wheat-alt,\n \"ankh\": $fa-var-ankh,\n \"hands-holding-child\": $fa-var-hands-holding-child,\n \"asterisk\": $fa-var-asterisk,\n \"square-check\": $fa-var-square-check,\n \"check-square\": $fa-var-check-square,\n \"peseta-sign\": $fa-var-peseta-sign,\n \"heading\": $fa-var-heading,\n \"header\": $fa-var-header,\n \"ghost\": $fa-var-ghost,\n \"list\": $fa-var-list,\n \"list-squares\": $fa-var-list-squares,\n \"square-phone-flip\": $fa-var-square-phone-flip,\n \"phone-square-alt\": $fa-var-phone-square-alt,\n \"cart-plus\": $fa-var-cart-plus,\n \"gamepad\": $fa-var-gamepad,\n \"circle-dot\": $fa-var-circle-dot,\n \"dot-circle\": $fa-var-dot-circle,\n \"face-dizzy\": $fa-var-face-dizzy,\n \"dizzy\": $fa-var-dizzy,\n \"egg\": $fa-var-egg,\n \"house-medical-circle-xmark\": $fa-var-house-medical-circle-xmark,\n \"campground\": $fa-var-campground,\n \"folder-plus\": $fa-var-folder-plus,\n \"futbol\": $fa-var-futbol,\n \"futbol-ball\": $fa-var-futbol-ball,\n \"soccer-ball\": $fa-var-soccer-ball,\n \"paintbrush\": $fa-var-paintbrush,\n \"paint-brush\": $fa-var-paint-brush,\n \"lock\": $fa-var-lock,\n \"gas-pump\": $fa-var-gas-pump,\n \"hot-tub-person\": $fa-var-hot-tub-person,\n \"hot-tub\": $fa-var-hot-tub,\n \"map-location\": $fa-var-map-location,\n \"map-marked\": $fa-var-map-marked,\n \"house-flood-water\": $fa-var-house-flood-water,\n \"tree\": $fa-var-tree,\n \"bridge-lock\": $fa-var-bridge-lock,\n \"sack-dollar\": $fa-var-sack-dollar,\n \"pen-to-square\": $fa-var-pen-to-square,\n \"edit\": $fa-var-edit,\n \"car-side\": $fa-var-car-side,\n \"share-nodes\": $fa-var-share-nodes,\n \"share-alt\": $fa-var-share-alt,\n \"heart-circle-minus\": $fa-var-heart-circle-minus,\n \"hourglass-half\": $fa-var-hourglass-half,\n \"hourglass-2\": $fa-var-hourglass-2,\n \"microscope\": $fa-var-microscope,\n \"sink\": $fa-var-sink,\n \"bag-shopping\": $fa-var-bag-shopping,\n \"shopping-bag\": $fa-var-shopping-bag,\n \"arrow-down-z-a\": $fa-var-arrow-down-z-a,\n \"sort-alpha-desc\": $fa-var-sort-alpha-desc,\n \"sort-alpha-down-alt\": $fa-var-sort-alpha-down-alt,\n \"mitten\": $fa-var-mitten,\n \"person-rays\": $fa-var-person-rays,\n \"users\": $fa-var-users,\n \"eye-slash\": $fa-var-eye-slash,\n \"flask-vial\": $fa-var-flask-vial,\n \"hand\": $fa-var-hand,\n \"hand-paper\": $fa-var-hand-paper,\n \"om\": $fa-var-om,\n \"worm\": $fa-var-worm,\n \"house-circle-xmark\": $fa-var-house-circle-xmark,\n \"plug\": $fa-var-plug,\n \"chevron-up\": $fa-var-chevron-up,\n \"hand-spock\": $fa-var-hand-spock,\n \"stopwatch\": $fa-var-stopwatch,\n \"face-kiss\": $fa-var-face-kiss,\n \"kiss\": $fa-var-kiss,\n \"bridge-circle-xmark\": $fa-var-bridge-circle-xmark,\n \"face-grin-tongue\": $fa-var-face-grin-tongue,\n \"grin-tongue\": $fa-var-grin-tongue,\n \"chess-bishop\": $fa-var-chess-bishop,\n \"face-grin-wink\": $fa-var-face-grin-wink,\n \"grin-wink\": $fa-var-grin-wink,\n \"ear-deaf\": $fa-var-ear-deaf,\n \"deaf\": $fa-var-deaf,\n \"deafness\": $fa-var-deafness,\n \"hard-of-hearing\": $fa-var-hard-of-hearing,\n \"road-circle-check\": $fa-var-road-circle-check,\n \"dice-five\": $fa-var-dice-five,\n \"square-rss\": $fa-var-square-rss,\n \"rss-square\": $fa-var-rss-square,\n \"land-mine-on\": $fa-var-land-mine-on,\n \"i-cursor\": $fa-var-i-cursor,\n \"stamp\": $fa-var-stamp,\n \"stairs\": $fa-var-stairs,\n \"i\": $fa-var-i,\n \"hryvnia-sign\": $fa-var-hryvnia-sign,\n \"hryvnia\": $fa-var-hryvnia,\n \"pills\": $fa-var-pills,\n \"face-grin-wide\": $fa-var-face-grin-wide,\n \"grin-alt\": $fa-var-grin-alt,\n \"tooth\": $fa-var-tooth,\n \"v\": $fa-var-v,\n \"bangladeshi-taka-sign\": $fa-var-bangladeshi-taka-sign,\n \"bicycle\": $fa-var-bicycle,\n \"staff-snake\": $fa-var-staff-snake,\n \"rod-asclepius\": $fa-var-rod-asclepius,\n \"rod-snake\": $fa-var-rod-snake,\n \"staff-aesculapius\": $fa-var-staff-aesculapius,\n \"head-side-cough-slash\": $fa-var-head-side-cough-slash,\n \"truck-medical\": $fa-var-truck-medical,\n \"ambulance\": $fa-var-ambulance,\n \"wheat-awn-circle-exclamation\": $fa-var-wheat-awn-circle-exclamation,\n \"snowman\": $fa-var-snowman,\n \"mortar-pestle\": $fa-var-mortar-pestle,\n \"road-barrier\": $fa-var-road-barrier,\n \"school\": $fa-var-school,\n \"igloo\": $fa-var-igloo,\n \"joint\": $fa-var-joint,\n \"angle-right\": $fa-var-angle-right,\n \"horse\": $fa-var-horse,\n \"q\": $fa-var-q,\n \"g\": $fa-var-g,\n \"notes-medical\": $fa-var-notes-medical,\n \"temperature-half\": $fa-var-temperature-half,\n \"temperature-2\": $fa-var-temperature-2,\n \"thermometer-2\": $fa-var-thermometer-2,\n \"thermometer-half\": $fa-var-thermometer-half,\n \"dong-sign\": $fa-var-dong-sign,\n \"capsules\": $fa-var-capsules,\n \"poo-storm\": $fa-var-poo-storm,\n \"poo-bolt\": $fa-var-poo-bolt,\n \"face-frown-open\": $fa-var-face-frown-open,\n \"frown-open\": $fa-var-frown-open,\n \"hand-point-up\": $fa-var-hand-point-up,\n \"money-bill\": $fa-var-money-bill,\n \"bookmark\": $fa-var-bookmark,\n \"align-justify\": $fa-var-align-justify,\n \"umbrella-beach\": $fa-var-umbrella-beach,\n \"helmet-un\": $fa-var-helmet-un,\n \"bullseye\": $fa-var-bullseye,\n \"bacon\": $fa-var-bacon,\n \"hand-point-down\": $fa-var-hand-point-down,\n \"arrow-up-from-bracket\": $fa-var-arrow-up-from-bracket,\n \"folder\": $fa-var-folder,\n \"folder-blank\": $fa-var-folder-blank,\n \"file-waveform\": $fa-var-file-waveform,\n \"file-medical-alt\": $fa-var-file-medical-alt,\n \"radiation\": $fa-var-radiation,\n \"chart-simple\": $fa-var-chart-simple,\n \"mars-stroke\": $fa-var-mars-stroke,\n \"vial\": $fa-var-vial,\n \"gauge\": $fa-var-gauge,\n \"dashboard\": $fa-var-dashboard,\n \"gauge-med\": $fa-var-gauge-med,\n \"tachometer-alt-average\": $fa-var-tachometer-alt-average,\n \"wand-magic-sparkles\": $fa-var-wand-magic-sparkles,\n \"magic-wand-sparkles\": $fa-var-magic-wand-sparkles,\n \"e\": $fa-var-e,\n \"pen-clip\": $fa-var-pen-clip,\n \"pen-alt\": $fa-var-pen-alt,\n \"bridge-circle-exclamation\": $fa-var-bridge-circle-exclamation,\n \"user\": $fa-var-user,\n \"school-circle-check\": $fa-var-school-circle-check,\n \"dumpster\": $fa-var-dumpster,\n \"van-shuttle\": $fa-var-van-shuttle,\n \"shuttle-van\": $fa-var-shuttle-van,\n \"building-user\": $fa-var-building-user,\n \"square-caret-left\": $fa-var-square-caret-left,\n \"caret-square-left\": $fa-var-caret-square-left,\n \"highlighter\": $fa-var-highlighter,\n \"key\": $fa-var-key,\n \"bullhorn\": $fa-var-bullhorn,\n \"globe\": $fa-var-globe,\n \"synagogue\": $fa-var-synagogue,\n \"person-half-dress\": $fa-var-person-half-dress,\n \"road-bridge\": $fa-var-road-bridge,\n \"location-arrow\": $fa-var-location-arrow,\n \"c\": $fa-var-c,\n \"tablet-button\": $fa-var-tablet-button,\n \"building-lock\": $fa-var-building-lock,\n \"pizza-slice\": $fa-var-pizza-slice,\n \"money-bill-wave\": $fa-var-money-bill-wave,\n \"chart-area\": $fa-var-chart-area,\n \"area-chart\": $fa-var-area-chart,\n \"house-flag\": $fa-var-house-flag,\n \"person-circle-minus\": $fa-var-person-circle-minus,\n \"ban\": $fa-var-ban,\n \"cancel\": $fa-var-cancel,\n \"camera-rotate\": $fa-var-camera-rotate,\n \"spray-can-sparkles\": $fa-var-spray-can-sparkles,\n \"air-freshener\": $fa-var-air-freshener,\n \"star\": $fa-var-star,\n \"repeat\": $fa-var-repeat,\n \"cross\": $fa-var-cross,\n \"box\": $fa-var-box,\n \"venus-mars\": $fa-var-venus-mars,\n \"arrow-pointer\": $fa-var-arrow-pointer,\n \"mouse-pointer\": $fa-var-mouse-pointer,\n \"maximize\": $fa-var-maximize,\n \"expand-arrows-alt\": $fa-var-expand-arrows-alt,\n \"charging-station\": $fa-var-charging-station,\n \"shapes\": $fa-var-shapes,\n \"triangle-circle-square\": $fa-var-triangle-circle-square,\n \"shuffle\": $fa-var-shuffle,\n \"random\": $fa-var-random,\n \"person-running\": $fa-var-person-running,\n \"running\": $fa-var-running,\n \"mobile-retro\": $fa-var-mobile-retro,\n \"grip-lines-vertical\": $fa-var-grip-lines-vertical,\n \"spider\": $fa-var-spider,\n \"hands-bound\": $fa-var-hands-bound,\n \"file-invoice-dollar\": $fa-var-file-invoice-dollar,\n \"plane-circle-exclamation\": $fa-var-plane-circle-exclamation,\n \"x-ray\": $fa-var-x-ray,\n \"spell-check\": $fa-var-spell-check,\n \"slash\": $fa-var-slash,\n \"computer-mouse\": $fa-var-computer-mouse,\n \"mouse\": $fa-var-mouse,\n \"arrow-right-to-bracket\": $fa-var-arrow-right-to-bracket,\n \"sign-in\": $fa-var-sign-in,\n \"shop-slash\": $fa-var-shop-slash,\n \"store-alt-slash\": $fa-var-store-alt-slash,\n \"server\": $fa-var-server,\n \"virus-covid-slash\": $fa-var-virus-covid-slash,\n \"shop-lock\": $fa-var-shop-lock,\n \"hourglass-start\": $fa-var-hourglass-start,\n \"hourglass-1\": $fa-var-hourglass-1,\n \"blender-phone\": $fa-var-blender-phone,\n \"building-wheat\": $fa-var-building-wheat,\n \"person-breastfeeding\": $fa-var-person-breastfeeding,\n \"right-to-bracket\": $fa-var-right-to-bracket,\n \"sign-in-alt\": $fa-var-sign-in-alt,\n \"venus\": $fa-var-venus,\n \"passport\": $fa-var-passport,\n \"thumbtack-slash\": $fa-var-thumbtack-slash,\n \"thumb-tack-slash\": $fa-var-thumb-tack-slash,\n \"heart-pulse\": $fa-var-heart-pulse,\n \"heartbeat\": $fa-var-heartbeat,\n \"people-carry-box\": $fa-var-people-carry-box,\n \"people-carry\": $fa-var-people-carry,\n \"temperature-high\": $fa-var-temperature-high,\n \"microchip\": $fa-var-microchip,\n \"crown\": $fa-var-crown,\n \"weight-hanging\": $fa-var-weight-hanging,\n \"xmarks-lines\": $fa-var-xmarks-lines,\n \"file-prescription\": $fa-var-file-prescription,\n \"weight-scale\": $fa-var-weight-scale,\n \"weight\": $fa-var-weight,\n \"user-group\": $fa-var-user-group,\n \"user-friends\": $fa-var-user-friends,\n \"arrow-up-a-z\": $fa-var-arrow-up-a-z,\n \"sort-alpha-up\": $fa-var-sort-alpha-up,\n \"chess-knight\": $fa-var-chess-knight,\n \"face-laugh-squint\": $fa-var-face-laugh-squint,\n \"laugh-squint\": $fa-var-laugh-squint,\n \"wheelchair\": $fa-var-wheelchair,\n \"circle-arrow-up\": $fa-var-circle-arrow-up,\n \"arrow-circle-up\": $fa-var-arrow-circle-up,\n \"toggle-on\": $fa-var-toggle-on,\n \"person-walking\": $fa-var-person-walking,\n \"walking\": $fa-var-walking,\n \"l\": $fa-var-l,\n \"fire\": $fa-var-fire,\n \"bed-pulse\": $fa-var-bed-pulse,\n \"procedures\": $fa-var-procedures,\n \"shuttle-space\": $fa-var-shuttle-space,\n \"space-shuttle\": $fa-var-space-shuttle,\n \"face-laugh\": $fa-var-face-laugh,\n \"laugh\": $fa-var-laugh,\n \"folder-open\": $fa-var-folder-open,\n \"heart-circle-plus\": $fa-var-heart-circle-plus,\n \"code-fork\": $fa-var-code-fork,\n \"city\": $fa-var-city,\n \"microphone-lines\": $fa-var-microphone-lines,\n \"microphone-alt\": $fa-var-microphone-alt,\n \"pepper-hot\": $fa-var-pepper-hot,\n \"unlock\": $fa-var-unlock,\n \"colon-sign\": $fa-var-colon-sign,\n \"headset\": $fa-var-headset,\n \"store-slash\": $fa-var-store-slash,\n \"road-circle-xmark\": $fa-var-road-circle-xmark,\n \"user-minus\": $fa-var-user-minus,\n \"mars-stroke-up\": $fa-var-mars-stroke-up,\n \"mars-stroke-v\": $fa-var-mars-stroke-v,\n \"champagne-glasses\": $fa-var-champagne-glasses,\n \"glass-cheers\": $fa-var-glass-cheers,\n \"clipboard\": $fa-var-clipboard,\n \"house-circle-exclamation\": $fa-var-house-circle-exclamation,\n \"file-arrow-up\": $fa-var-file-arrow-up,\n \"file-upload\": $fa-var-file-upload,\n \"wifi\": $fa-var-wifi,\n \"wifi-3\": $fa-var-wifi-3,\n \"wifi-strong\": $fa-var-wifi-strong,\n \"bath\": $fa-var-bath,\n \"bathtub\": $fa-var-bathtub,\n \"underline\": $fa-var-underline,\n \"user-pen\": $fa-var-user-pen,\n \"user-edit\": $fa-var-user-edit,\n \"signature\": $fa-var-signature,\n \"stroopwafel\": $fa-var-stroopwafel,\n \"bold\": $fa-var-bold,\n \"anchor-lock\": $fa-var-anchor-lock,\n \"building-ngo\": $fa-var-building-ngo,\n \"manat-sign\": $fa-var-manat-sign,\n \"not-equal\": $fa-var-not-equal,\n \"border-top-left\": $fa-var-border-top-left,\n \"border-style\": $fa-var-border-style,\n \"map-location-dot\": $fa-var-map-location-dot,\n \"map-marked-alt\": $fa-var-map-marked-alt,\n \"jedi\": $fa-var-jedi,\n \"square-poll-vertical\": $fa-var-square-poll-vertical,\n \"poll\": $fa-var-poll,\n \"mug-hot\": $fa-var-mug-hot,\n \"car-battery\": $fa-var-car-battery,\n \"battery-car\": $fa-var-battery-car,\n \"gift\": $fa-var-gift,\n \"dice-two\": $fa-var-dice-two,\n \"chess-queen\": $fa-var-chess-queen,\n \"glasses\": $fa-var-glasses,\n \"chess-board\": $fa-var-chess-board,\n \"building-circle-check\": $fa-var-building-circle-check,\n \"person-chalkboard\": $fa-var-person-chalkboard,\n \"mars-stroke-right\": $fa-var-mars-stroke-right,\n \"mars-stroke-h\": $fa-var-mars-stroke-h,\n \"hand-back-fist\": $fa-var-hand-back-fist,\n \"hand-rock\": $fa-var-hand-rock,\n \"square-caret-up\": $fa-var-square-caret-up,\n \"caret-square-up\": $fa-var-caret-square-up,\n \"cloud-showers-water\": $fa-var-cloud-showers-water,\n \"chart-bar\": $fa-var-chart-bar,\n \"bar-chart\": $fa-var-bar-chart,\n \"hands-bubbles\": $fa-var-hands-bubbles,\n \"hands-wash\": $fa-var-hands-wash,\n \"less-than-equal\": $fa-var-less-than-equal,\n \"train\": $fa-var-train,\n \"eye-low-vision\": $fa-var-eye-low-vision,\n \"low-vision\": $fa-var-low-vision,\n \"crow\": $fa-var-crow,\n \"sailboat\": $fa-var-sailboat,\n \"window-restore\": $fa-var-window-restore,\n \"square-plus\": $fa-var-square-plus,\n \"plus-square\": $fa-var-plus-square,\n \"torii-gate\": $fa-var-torii-gate,\n \"frog\": $fa-var-frog,\n \"bucket\": $fa-var-bucket,\n \"image\": $fa-var-image,\n \"microphone\": $fa-var-microphone,\n \"cow\": $fa-var-cow,\n \"caret-up\": $fa-var-caret-up,\n \"screwdriver\": $fa-var-screwdriver,\n \"folder-closed\": $fa-var-folder-closed,\n \"house-tsunami\": $fa-var-house-tsunami,\n \"square-nfi\": $fa-var-square-nfi,\n \"arrow-up-from-ground-water\": $fa-var-arrow-up-from-ground-water,\n \"martini-glass\": $fa-var-martini-glass,\n \"glass-martini-alt\": $fa-var-glass-martini-alt,\n \"square-binary\": $fa-var-square-binary,\n \"rotate-left\": $fa-var-rotate-left,\n \"rotate-back\": $fa-var-rotate-back,\n \"rotate-backward\": $fa-var-rotate-backward,\n \"undo-alt\": $fa-var-undo-alt,\n \"table-columns\": $fa-var-table-columns,\n \"columns\": $fa-var-columns,\n \"lemon\": $fa-var-lemon,\n \"head-side-mask\": $fa-var-head-side-mask,\n \"handshake\": $fa-var-handshake,\n \"gem\": $fa-var-gem,\n \"dolly\": $fa-var-dolly,\n \"dolly-box\": $fa-var-dolly-box,\n \"smoking\": $fa-var-smoking,\n \"minimize\": $fa-var-minimize,\n \"compress-arrows-alt\": $fa-var-compress-arrows-alt,\n \"monument\": $fa-var-monument,\n \"snowplow\": $fa-var-snowplow,\n \"angles-right\": $fa-var-angles-right,\n \"angle-double-right\": $fa-var-angle-double-right,\n \"cannabis\": $fa-var-cannabis,\n \"circle-play\": $fa-var-circle-play,\n \"play-circle\": $fa-var-play-circle,\n \"tablets\": $fa-var-tablets,\n \"ethernet\": $fa-var-ethernet,\n \"euro-sign\": $fa-var-euro-sign,\n \"eur\": $fa-var-eur,\n \"euro\": $fa-var-euro,\n \"chair\": $fa-var-chair,\n \"circle-check\": $fa-var-circle-check,\n \"check-circle\": $fa-var-check-circle,\n \"circle-stop\": $fa-var-circle-stop,\n \"stop-circle\": $fa-var-stop-circle,\n \"compass-drafting\": $fa-var-compass-drafting,\n \"drafting-compass\": $fa-var-drafting-compass,\n \"plate-wheat\": $fa-var-plate-wheat,\n \"icicles\": $fa-var-icicles,\n \"person-shelter\": $fa-var-person-shelter,\n \"neuter\": $fa-var-neuter,\n \"id-badge\": $fa-var-id-badge,\n \"marker\": $fa-var-marker,\n \"face-laugh-beam\": $fa-var-face-laugh-beam,\n \"laugh-beam\": $fa-var-laugh-beam,\n \"helicopter-symbol\": $fa-var-helicopter-symbol,\n \"universal-access\": $fa-var-universal-access,\n \"circle-chevron-up\": $fa-var-circle-chevron-up,\n \"chevron-circle-up\": $fa-var-chevron-circle-up,\n \"lari-sign\": $fa-var-lari-sign,\n \"volcano\": $fa-var-volcano,\n \"person-walking-dashed-line-arrow-right\": $fa-var-person-walking-dashed-line-arrow-right,\n \"sterling-sign\": $fa-var-sterling-sign,\n \"gbp\": $fa-var-gbp,\n \"pound-sign\": $fa-var-pound-sign,\n \"viruses\": $fa-var-viruses,\n \"square-person-confined\": $fa-var-square-person-confined,\n \"user-tie\": $fa-var-user-tie,\n \"arrow-down-long\": $fa-var-arrow-down-long,\n \"long-arrow-down\": $fa-var-long-arrow-down,\n \"tent-arrow-down-to-line\": $fa-var-tent-arrow-down-to-line,\n \"certificate\": $fa-var-certificate,\n \"reply-all\": $fa-var-reply-all,\n \"mail-reply-all\": $fa-var-mail-reply-all,\n \"suitcase\": $fa-var-suitcase,\n \"person-skating\": $fa-var-person-skating,\n \"skating\": $fa-var-skating,\n \"filter-circle-dollar\": $fa-var-filter-circle-dollar,\n \"funnel-dollar\": $fa-var-funnel-dollar,\n \"camera-retro\": $fa-var-camera-retro,\n \"circle-arrow-down\": $fa-var-circle-arrow-down,\n \"arrow-circle-down\": $fa-var-arrow-circle-down,\n \"file-import\": $fa-var-file-import,\n \"arrow-right-to-file\": $fa-var-arrow-right-to-file,\n \"square-arrow-up-right\": $fa-var-square-arrow-up-right,\n \"external-link-square\": $fa-var-external-link-square,\n \"box-open\": $fa-var-box-open,\n \"scroll\": $fa-var-scroll,\n \"spa\": $fa-var-spa,\n \"location-pin-lock\": $fa-var-location-pin-lock,\n \"pause\": $fa-var-pause,\n \"hill-avalanche\": $fa-var-hill-avalanche,\n \"temperature-empty\": $fa-var-temperature-empty,\n \"temperature-0\": $fa-var-temperature-0,\n \"thermometer-0\": $fa-var-thermometer-0,\n \"thermometer-empty\": $fa-var-thermometer-empty,\n \"bomb\": $fa-var-bomb,\n \"registered\": $fa-var-registered,\n \"address-card\": $fa-var-address-card,\n \"contact-card\": $fa-var-contact-card,\n \"vcard\": $fa-var-vcard,\n \"scale-unbalanced-flip\": $fa-var-scale-unbalanced-flip,\n \"balance-scale-right\": $fa-var-balance-scale-right,\n \"subscript\": $fa-var-subscript,\n \"diamond-turn-right\": $fa-var-diamond-turn-right,\n \"directions\": $fa-var-directions,\n \"burst\": $fa-var-burst,\n \"house-laptop\": $fa-var-house-laptop,\n \"laptop-house\": $fa-var-laptop-house,\n \"face-tired\": $fa-var-face-tired,\n \"tired\": $fa-var-tired,\n \"money-bills\": $fa-var-money-bills,\n \"smog\": $fa-var-smog,\n \"crutch\": $fa-var-crutch,\n \"cloud-arrow-up\": $fa-var-cloud-arrow-up,\n \"cloud-upload\": $fa-var-cloud-upload,\n \"cloud-upload-alt\": $fa-var-cloud-upload-alt,\n \"palette\": $fa-var-palette,\n \"arrows-turn-right\": $fa-var-arrows-turn-right,\n \"vest\": $fa-var-vest,\n \"ferry\": $fa-var-ferry,\n \"arrows-down-to-people\": $fa-var-arrows-down-to-people,\n \"seedling\": $fa-var-seedling,\n \"sprout\": $fa-var-sprout,\n \"left-right\": $fa-var-left-right,\n \"arrows-alt-h\": $fa-var-arrows-alt-h,\n \"boxes-packing\": $fa-var-boxes-packing,\n \"circle-arrow-left\": $fa-var-circle-arrow-left,\n \"arrow-circle-left\": $fa-var-arrow-circle-left,\n \"group-arrows-rotate\": $fa-var-group-arrows-rotate,\n \"bowl-food\": $fa-var-bowl-food,\n \"candy-cane\": $fa-var-candy-cane,\n \"arrow-down-wide-short\": $fa-var-arrow-down-wide-short,\n \"sort-amount-asc\": $fa-var-sort-amount-asc,\n \"sort-amount-down\": $fa-var-sort-amount-down,\n \"cloud-bolt\": $fa-var-cloud-bolt,\n \"thunderstorm\": $fa-var-thunderstorm,\n \"text-slash\": $fa-var-text-slash,\n \"remove-format\": $fa-var-remove-format,\n \"face-smile-wink\": $fa-var-face-smile-wink,\n \"smile-wink\": $fa-var-smile-wink,\n \"file-word\": $fa-var-file-word,\n \"file-powerpoint\": $fa-var-file-powerpoint,\n \"arrows-left-right\": $fa-var-arrows-left-right,\n \"arrows-h\": $fa-var-arrows-h,\n \"house-lock\": $fa-var-house-lock,\n \"cloud-arrow-down\": $fa-var-cloud-arrow-down,\n \"cloud-download\": $fa-var-cloud-download,\n \"cloud-download-alt\": $fa-var-cloud-download-alt,\n \"children\": $fa-var-children,\n \"chalkboard\": $fa-var-chalkboard,\n \"blackboard\": $fa-var-blackboard,\n \"user-large-slash\": $fa-var-user-large-slash,\n \"user-alt-slash\": $fa-var-user-alt-slash,\n \"envelope-open\": $fa-var-envelope-open,\n \"handshake-simple-slash\": $fa-var-handshake-simple-slash,\n \"handshake-alt-slash\": $fa-var-handshake-alt-slash,\n \"mattress-pillow\": $fa-var-mattress-pillow,\n \"guarani-sign\": $fa-var-guarani-sign,\n \"arrows-rotate\": $fa-var-arrows-rotate,\n \"refresh\": $fa-var-refresh,\n \"sync\": $fa-var-sync,\n \"fire-extinguisher\": $fa-var-fire-extinguisher,\n \"cruzeiro-sign\": $fa-var-cruzeiro-sign,\n \"greater-than-equal\": $fa-var-greater-than-equal,\n \"shield-halved\": $fa-var-shield-halved,\n \"shield-alt\": $fa-var-shield-alt,\n \"book-atlas\": $fa-var-book-atlas,\n \"atlas\": $fa-var-atlas,\n \"virus\": $fa-var-virus,\n \"envelope-circle-check\": $fa-var-envelope-circle-check,\n \"layer-group\": $fa-var-layer-group,\n \"arrows-to-dot\": $fa-var-arrows-to-dot,\n \"archway\": $fa-var-archway,\n \"heart-circle-check\": $fa-var-heart-circle-check,\n \"house-chimney-crack\": $fa-var-house-chimney-crack,\n \"house-damage\": $fa-var-house-damage,\n \"file-zipper\": $fa-var-file-zipper,\n \"file-archive\": $fa-var-file-archive,\n \"square\": $fa-var-square,\n \"martini-glass-empty\": $fa-var-martini-glass-empty,\n \"glass-martini\": $fa-var-glass-martini,\n \"couch\": $fa-var-couch,\n \"cedi-sign\": $fa-var-cedi-sign,\n \"italic\": $fa-var-italic,\n \"table-cells-column-lock\": $fa-var-table-cells-column-lock,\n \"church\": $fa-var-church,\n \"comments-dollar\": $fa-var-comments-dollar,\n \"democrat\": $fa-var-democrat,\n \"z\": $fa-var-z,\n \"person-skiing\": $fa-var-person-skiing,\n \"skiing\": $fa-var-skiing,\n \"road-lock\": $fa-var-road-lock,\n \"a\": $fa-var-a,\n \"temperature-arrow-down\": $fa-var-temperature-arrow-down,\n \"temperature-down\": $fa-var-temperature-down,\n \"feather-pointed\": $fa-var-feather-pointed,\n \"feather-alt\": $fa-var-feather-alt,\n \"p\": $fa-var-p,\n \"snowflake\": $fa-var-snowflake,\n \"newspaper\": $fa-var-newspaper,\n \"rectangle-ad\": $fa-var-rectangle-ad,\n \"ad\": $fa-var-ad,\n \"circle-arrow-right\": $fa-var-circle-arrow-right,\n \"arrow-circle-right\": $fa-var-arrow-circle-right,\n \"filter-circle-xmark\": $fa-var-filter-circle-xmark,\n \"locust\": $fa-var-locust,\n \"sort\": $fa-var-sort,\n \"unsorted\": $fa-var-unsorted,\n \"list-ol\": $fa-var-list-ol,\n \"list-1-2\": $fa-var-list-1-2,\n \"list-numeric\": $fa-var-list-numeric,\n \"person-dress-burst\": $fa-var-person-dress-burst,\n \"money-check-dollar\": $fa-var-money-check-dollar,\n \"money-check-alt\": $fa-var-money-check-alt,\n \"vector-square\": $fa-var-vector-square,\n \"bread-slice\": $fa-var-bread-slice,\n \"language\": $fa-var-language,\n \"face-kiss-wink-heart\": $fa-var-face-kiss-wink-heart,\n \"kiss-wink-heart\": $fa-var-kiss-wink-heart,\n \"filter\": $fa-var-filter,\n \"question\": $fa-var-question,\n \"file-signature\": $fa-var-file-signature,\n \"up-down-left-right\": $fa-var-up-down-left-right,\n \"arrows-alt\": $fa-var-arrows-alt,\n \"house-chimney-user\": $fa-var-house-chimney-user,\n \"hand-holding-heart\": $fa-var-hand-holding-heart,\n \"puzzle-piece\": $fa-var-puzzle-piece,\n \"money-check\": $fa-var-money-check,\n \"star-half-stroke\": $fa-var-star-half-stroke,\n \"star-half-alt\": $fa-var-star-half-alt,\n \"code\": $fa-var-code,\n \"whiskey-glass\": $fa-var-whiskey-glass,\n \"glass-whiskey\": $fa-var-glass-whiskey,\n \"building-circle-exclamation\": $fa-var-building-circle-exclamation,\n \"magnifying-glass-chart\": $fa-var-magnifying-glass-chart,\n \"arrow-up-right-from-square\": $fa-var-arrow-up-right-from-square,\n \"external-link\": $fa-var-external-link,\n \"cubes-stacked\": $fa-var-cubes-stacked,\n \"won-sign\": $fa-var-won-sign,\n \"krw\": $fa-var-krw,\n \"won\": $fa-var-won,\n \"virus-covid\": $fa-var-virus-covid,\n \"austral-sign\": $fa-var-austral-sign,\n \"f\": $fa-var-f,\n \"leaf\": $fa-var-leaf,\n \"road\": $fa-var-road,\n \"taxi\": $fa-var-taxi,\n \"cab\": $fa-var-cab,\n \"person-circle-plus\": $fa-var-person-circle-plus,\n \"chart-pie\": $fa-var-chart-pie,\n \"pie-chart\": $fa-var-pie-chart,\n \"bolt-lightning\": $fa-var-bolt-lightning,\n \"sack-xmark\": $fa-var-sack-xmark,\n \"file-excel\": $fa-var-file-excel,\n \"file-contract\": $fa-var-file-contract,\n \"fish-fins\": $fa-var-fish-fins,\n \"building-flag\": $fa-var-building-flag,\n \"face-grin-beam\": $fa-var-face-grin-beam,\n \"grin-beam\": $fa-var-grin-beam,\n \"object-ungroup\": $fa-var-object-ungroup,\n \"poop\": $fa-var-poop,\n \"location-pin\": $fa-var-location-pin,\n \"map-marker\": $fa-var-map-marker,\n \"kaaba\": $fa-var-kaaba,\n \"toilet-paper\": $fa-var-toilet-paper,\n \"helmet-safety\": $fa-var-helmet-safety,\n \"hard-hat\": $fa-var-hard-hat,\n \"hat-hard\": $fa-var-hat-hard,\n \"eject\": $fa-var-eject,\n \"circle-right\": $fa-var-circle-right,\n \"arrow-alt-circle-right\": $fa-var-arrow-alt-circle-right,\n \"plane-circle-check\": $fa-var-plane-circle-check,\n \"face-rolling-eyes\": $fa-var-face-rolling-eyes,\n \"meh-rolling-eyes\": $fa-var-meh-rolling-eyes,\n \"object-group\": $fa-var-object-group,\n \"chart-line\": $fa-var-chart-line,\n \"line-chart\": $fa-var-line-chart,\n \"mask-ventilator\": $fa-var-mask-ventilator,\n \"arrow-right\": $fa-var-arrow-right,\n \"signs-post\": $fa-var-signs-post,\n \"map-signs\": $fa-var-map-signs,\n \"cash-register\": $fa-var-cash-register,\n \"person-circle-question\": $fa-var-person-circle-question,\n \"h\": $fa-var-h,\n \"tarp\": $fa-var-tarp,\n \"screwdriver-wrench\": $fa-var-screwdriver-wrench,\n \"tools\": $fa-var-tools,\n \"arrows-to-eye\": $fa-var-arrows-to-eye,\n \"plug-circle-bolt\": $fa-var-plug-circle-bolt,\n \"heart\": $fa-var-heart,\n \"mars-and-venus\": $fa-var-mars-and-venus,\n \"house-user\": $fa-var-house-user,\n \"home-user\": $fa-var-home-user,\n \"dumpster-fire\": $fa-var-dumpster-fire,\n \"house-crack\": $fa-var-house-crack,\n \"martini-glass-citrus\": $fa-var-martini-glass-citrus,\n \"cocktail\": $fa-var-cocktail,\n \"face-surprise\": $fa-var-face-surprise,\n \"surprise\": $fa-var-surprise,\n \"bottle-water\": $fa-var-bottle-water,\n \"circle-pause\": $fa-var-circle-pause,\n \"pause-circle\": $fa-var-pause-circle,\n \"toilet-paper-slash\": $fa-var-toilet-paper-slash,\n \"apple-whole\": $fa-var-apple-whole,\n \"apple-alt\": $fa-var-apple-alt,\n \"kitchen-set\": $fa-var-kitchen-set,\n \"r\": $fa-var-r,\n \"temperature-quarter\": $fa-var-temperature-quarter,\n \"temperature-1\": $fa-var-temperature-1,\n \"thermometer-1\": $fa-var-thermometer-1,\n \"thermometer-quarter\": $fa-var-thermometer-quarter,\n \"cube\": $fa-var-cube,\n \"bitcoin-sign\": $fa-var-bitcoin-sign,\n \"shield-dog\": $fa-var-shield-dog,\n \"solar-panel\": $fa-var-solar-panel,\n \"lock-open\": $fa-var-lock-open,\n \"elevator\": $fa-var-elevator,\n \"money-bill-transfer\": $fa-var-money-bill-transfer,\n \"money-bill-trend-up\": $fa-var-money-bill-trend-up,\n \"house-flood-water-circle-arrow-right\": $fa-var-house-flood-water-circle-arrow-right,\n \"square-poll-horizontal\": $fa-var-square-poll-horizontal,\n \"poll-h\": $fa-var-poll-h,\n \"circle\": $fa-var-circle,\n \"backward-fast\": $fa-var-backward-fast,\n \"fast-backward\": $fa-var-fast-backward,\n \"recycle\": $fa-var-recycle,\n \"user-astronaut\": $fa-var-user-astronaut,\n \"plane-slash\": $fa-var-plane-slash,\n \"trademark\": $fa-var-trademark,\n \"basketball\": $fa-var-basketball,\n \"basketball-ball\": $fa-var-basketball-ball,\n \"satellite-dish\": $fa-var-satellite-dish,\n \"circle-up\": $fa-var-circle-up,\n \"arrow-alt-circle-up\": $fa-var-arrow-alt-circle-up,\n \"mobile-screen-button\": $fa-var-mobile-screen-button,\n \"mobile-alt\": $fa-var-mobile-alt,\n \"volume-high\": $fa-var-volume-high,\n \"volume-up\": $fa-var-volume-up,\n \"users-rays\": $fa-var-users-rays,\n \"wallet\": $fa-var-wallet,\n \"clipboard-check\": $fa-var-clipboard-check,\n \"file-audio\": $fa-var-file-audio,\n \"burger\": $fa-var-burger,\n \"hamburger\": $fa-var-hamburger,\n \"wrench\": $fa-var-wrench,\n \"bugs\": $fa-var-bugs,\n \"rupee-sign\": $fa-var-rupee-sign,\n \"rupee\": $fa-var-rupee,\n \"file-image\": $fa-var-file-image,\n \"circle-question\": $fa-var-circle-question,\n \"question-circle\": $fa-var-question-circle,\n \"plane-departure\": $fa-var-plane-departure,\n \"handshake-slash\": $fa-var-handshake-slash,\n \"book-bookmark\": $fa-var-book-bookmark,\n \"code-branch\": $fa-var-code-branch,\n \"hat-cowboy\": $fa-var-hat-cowboy,\n \"bridge\": $fa-var-bridge,\n \"phone-flip\": $fa-var-phone-flip,\n \"phone-alt\": $fa-var-phone-alt,\n \"truck-front\": $fa-var-truck-front,\n \"cat\": $fa-var-cat,\n \"anchor-circle-exclamation\": $fa-var-anchor-circle-exclamation,\n \"truck-field\": $fa-var-truck-field,\n \"route\": $fa-var-route,\n \"clipboard-question\": $fa-var-clipboard-question,\n \"panorama\": $fa-var-panorama,\n \"comment-medical\": $fa-var-comment-medical,\n \"teeth-open\": $fa-var-teeth-open,\n \"file-circle-minus\": $fa-var-file-circle-minus,\n \"tags\": $fa-var-tags,\n \"wine-glass\": $fa-var-wine-glass,\n \"forward-fast\": $fa-var-forward-fast,\n \"fast-forward\": $fa-var-fast-forward,\n \"face-meh-blank\": $fa-var-face-meh-blank,\n \"meh-blank\": $fa-var-meh-blank,\n \"square-parking\": $fa-var-square-parking,\n \"parking\": $fa-var-parking,\n \"house-signal\": $fa-var-house-signal,\n \"bars-progress\": $fa-var-bars-progress,\n \"tasks-alt\": $fa-var-tasks-alt,\n \"faucet-drip\": $fa-var-faucet-drip,\n \"cart-flatbed\": $fa-var-cart-flatbed,\n \"dolly-flatbed\": $fa-var-dolly-flatbed,\n \"ban-smoking\": $fa-var-ban-smoking,\n \"smoking-ban\": $fa-var-smoking-ban,\n \"terminal\": $fa-var-terminal,\n \"mobile-button\": $fa-var-mobile-button,\n \"house-medical-flag\": $fa-var-house-medical-flag,\n \"basket-shopping\": $fa-var-basket-shopping,\n \"shopping-basket\": $fa-var-shopping-basket,\n \"tape\": $fa-var-tape,\n \"bus-simple\": $fa-var-bus-simple,\n \"bus-alt\": $fa-var-bus-alt,\n \"eye\": $fa-var-eye,\n \"face-sad-cry\": $fa-var-face-sad-cry,\n \"sad-cry\": $fa-var-sad-cry,\n \"audio-description\": $fa-var-audio-description,\n \"person-military-to-person\": $fa-var-person-military-to-person,\n \"file-shield\": $fa-var-file-shield,\n \"user-slash\": $fa-var-user-slash,\n \"pen\": $fa-var-pen,\n \"tower-observation\": $fa-var-tower-observation,\n \"file-code\": $fa-var-file-code,\n \"signal\": $fa-var-signal,\n \"signal-5\": $fa-var-signal-5,\n \"signal-perfect\": $fa-var-signal-perfect,\n \"bus\": $fa-var-bus,\n \"heart-circle-xmark\": $fa-var-heart-circle-xmark,\n \"house-chimney\": $fa-var-house-chimney,\n \"home-lg\": $fa-var-home-lg,\n \"window-maximize\": $fa-var-window-maximize,\n \"face-frown\": $fa-var-face-frown,\n \"frown\": $fa-var-frown,\n \"prescription\": $fa-var-prescription,\n \"shop\": $fa-var-shop,\n \"store-alt\": $fa-var-store-alt,\n \"floppy-disk\": $fa-var-floppy-disk,\n \"save\": $fa-var-save,\n \"vihara\": $fa-var-vihara,\n \"scale-unbalanced\": $fa-var-scale-unbalanced,\n \"balance-scale-left\": $fa-var-balance-scale-left,\n \"sort-up\": $fa-var-sort-up,\n \"sort-asc\": $fa-var-sort-asc,\n \"comment-dots\": $fa-var-comment-dots,\n \"commenting\": $fa-var-commenting,\n \"plant-wilt\": $fa-var-plant-wilt,\n \"diamond\": $fa-var-diamond,\n \"face-grin-squint\": $fa-var-face-grin-squint,\n \"grin-squint\": $fa-var-grin-squint,\n \"hand-holding-dollar\": $fa-var-hand-holding-dollar,\n \"hand-holding-usd\": $fa-var-hand-holding-usd,\n \"chart-diagram\": $fa-var-chart-diagram,\n \"bacterium\": $fa-var-bacterium,\n \"hand-pointer\": $fa-var-hand-pointer,\n \"drum-steelpan\": $fa-var-drum-steelpan,\n \"hand-scissors\": $fa-var-hand-scissors,\n \"hands-praying\": $fa-var-hands-praying,\n \"praying-hands\": $fa-var-praying-hands,\n \"arrow-rotate-right\": $fa-var-arrow-rotate-right,\n \"arrow-right-rotate\": $fa-var-arrow-right-rotate,\n \"arrow-rotate-forward\": $fa-var-arrow-rotate-forward,\n \"redo\": $fa-var-redo,\n \"biohazard\": $fa-var-biohazard,\n \"location-crosshairs\": $fa-var-location-crosshairs,\n \"location\": $fa-var-location,\n \"mars-double\": $fa-var-mars-double,\n \"child-dress\": $fa-var-child-dress,\n \"users-between-lines\": $fa-var-users-between-lines,\n \"lungs-virus\": $fa-var-lungs-virus,\n \"face-grin-tears\": $fa-var-face-grin-tears,\n \"grin-tears\": $fa-var-grin-tears,\n \"phone\": $fa-var-phone,\n \"calendar-xmark\": $fa-var-calendar-xmark,\n \"calendar-times\": $fa-var-calendar-times,\n \"child-reaching\": $fa-var-child-reaching,\n \"head-side-virus\": $fa-var-head-side-virus,\n \"user-gear\": $fa-var-user-gear,\n \"user-cog\": $fa-var-user-cog,\n \"arrow-up-1-9\": $fa-var-arrow-up-1-9,\n \"sort-numeric-up\": $fa-var-sort-numeric-up,\n \"door-closed\": $fa-var-door-closed,\n \"shield-virus\": $fa-var-shield-virus,\n \"dice-six\": $fa-var-dice-six,\n \"mosquito-net\": $fa-var-mosquito-net,\n \"file-fragment\": $fa-var-file-fragment,\n \"bridge-water\": $fa-var-bridge-water,\n \"person-booth\": $fa-var-person-booth,\n \"text-width\": $fa-var-text-width,\n \"hat-wizard\": $fa-var-hat-wizard,\n \"pen-fancy\": $fa-var-pen-fancy,\n \"person-digging\": $fa-var-person-digging,\n \"digging\": $fa-var-digging,\n \"trash\": $fa-var-trash,\n \"gauge-simple\": $fa-var-gauge-simple,\n \"gauge-simple-med\": $fa-var-gauge-simple-med,\n \"tachometer-average\": $fa-var-tachometer-average,\n \"book-medical\": $fa-var-book-medical,\n \"poo\": $fa-var-poo,\n \"quote-right\": $fa-var-quote-right,\n \"quote-right-alt\": $fa-var-quote-right-alt,\n \"shirt\": $fa-var-shirt,\n \"t-shirt\": $fa-var-t-shirt,\n \"tshirt\": $fa-var-tshirt,\n \"cubes\": $fa-var-cubes,\n \"divide\": $fa-var-divide,\n \"tenge-sign\": $fa-var-tenge-sign,\n \"tenge\": $fa-var-tenge,\n \"headphones\": $fa-var-headphones,\n \"hands-holding\": $fa-var-hands-holding,\n \"hands-clapping\": $fa-var-hands-clapping,\n \"republican\": $fa-var-republican,\n \"arrow-left\": $fa-var-arrow-left,\n \"person-circle-xmark\": $fa-var-person-circle-xmark,\n \"ruler\": $fa-var-ruler,\n \"align-left\": $fa-var-align-left,\n \"dice-d6\": $fa-var-dice-d6,\n \"restroom\": $fa-var-restroom,\n \"j\": $fa-var-j,\n \"users-viewfinder\": $fa-var-users-viewfinder,\n \"file-video\": $fa-var-file-video,\n \"up-right-from-square\": $fa-var-up-right-from-square,\n \"external-link-alt\": $fa-var-external-link-alt,\n \"table-cells\": $fa-var-table-cells,\n \"th\": $fa-var-th,\n \"file-pdf\": $fa-var-file-pdf,\n \"book-bible\": $fa-var-book-bible,\n \"bible\": $fa-var-bible,\n \"o\": $fa-var-o,\n \"suitcase-medical\": $fa-var-suitcase-medical,\n \"medkit\": $fa-var-medkit,\n \"user-secret\": $fa-var-user-secret,\n \"otter\": $fa-var-otter,\n \"person-dress\": $fa-var-person-dress,\n \"female\": $fa-var-female,\n \"comment-dollar\": $fa-var-comment-dollar,\n \"business-time\": $fa-var-business-time,\n \"briefcase-clock\": $fa-var-briefcase-clock,\n \"table-cells-large\": $fa-var-table-cells-large,\n \"th-large\": $fa-var-th-large,\n \"book-tanakh\": $fa-var-book-tanakh,\n \"tanakh\": $fa-var-tanakh,\n \"phone-volume\": $fa-var-phone-volume,\n \"volume-control-phone\": $fa-var-volume-control-phone,\n \"hat-cowboy-side\": $fa-var-hat-cowboy-side,\n \"clipboard-user\": $fa-var-clipboard-user,\n \"child\": $fa-var-child,\n \"lira-sign\": $fa-var-lira-sign,\n \"satellite\": $fa-var-satellite,\n \"plane-lock\": $fa-var-plane-lock,\n \"tag\": $fa-var-tag,\n \"comment\": $fa-var-comment,\n \"cake-candles\": $fa-var-cake-candles,\n \"birthday-cake\": $fa-var-birthday-cake,\n \"cake\": $fa-var-cake,\n \"envelope\": $fa-var-envelope,\n \"angles-up\": $fa-var-angles-up,\n \"angle-double-up\": $fa-var-angle-double-up,\n \"paperclip\": $fa-var-paperclip,\n \"arrow-right-to-city\": $fa-var-arrow-right-to-city,\n \"ribbon\": $fa-var-ribbon,\n \"lungs\": $fa-var-lungs,\n \"arrow-up-9-1\": $fa-var-arrow-up-9-1,\n \"sort-numeric-up-alt\": $fa-var-sort-numeric-up-alt,\n \"litecoin-sign\": $fa-var-litecoin-sign,\n \"border-none\": $fa-var-border-none,\n \"circle-nodes\": $fa-var-circle-nodes,\n \"parachute-box\": $fa-var-parachute-box,\n \"indent\": $fa-var-indent,\n \"truck-field-un\": $fa-var-truck-field-un,\n \"hourglass\": $fa-var-hourglass,\n \"hourglass-empty\": $fa-var-hourglass-empty,\n \"mountain\": $fa-var-mountain,\n \"user-doctor\": $fa-var-user-doctor,\n \"user-md\": $fa-var-user-md,\n \"circle-info\": $fa-var-circle-info,\n \"info-circle\": $fa-var-info-circle,\n \"cloud-meatball\": $fa-var-cloud-meatball,\n \"camera\": $fa-var-camera,\n \"camera-alt\": $fa-var-camera-alt,\n \"square-virus\": $fa-var-square-virus,\n \"meteor\": $fa-var-meteor,\n \"car-on\": $fa-var-car-on,\n \"sleigh\": $fa-var-sleigh,\n \"arrow-down-1-9\": $fa-var-arrow-down-1-9,\n \"sort-numeric-asc\": $fa-var-sort-numeric-asc,\n \"sort-numeric-down\": $fa-var-sort-numeric-down,\n \"hand-holding-droplet\": $fa-var-hand-holding-droplet,\n \"hand-holding-water\": $fa-var-hand-holding-water,\n \"water\": $fa-var-water,\n \"calendar-check\": $fa-var-calendar-check,\n \"braille\": $fa-var-braille,\n \"prescription-bottle-medical\": $fa-var-prescription-bottle-medical,\n \"prescription-bottle-alt\": $fa-var-prescription-bottle-alt,\n \"landmark\": $fa-var-landmark,\n \"truck\": $fa-var-truck,\n \"crosshairs\": $fa-var-crosshairs,\n \"person-cane\": $fa-var-person-cane,\n \"tent\": $fa-var-tent,\n \"vest-patches\": $fa-var-vest-patches,\n \"check-double\": $fa-var-check-double,\n \"arrow-down-a-z\": $fa-var-arrow-down-a-z,\n \"sort-alpha-asc\": $fa-var-sort-alpha-asc,\n \"sort-alpha-down\": $fa-var-sort-alpha-down,\n \"money-bill-wheat\": $fa-var-money-bill-wheat,\n \"cookie\": $fa-var-cookie,\n \"arrow-rotate-left\": $fa-var-arrow-rotate-left,\n \"arrow-left-rotate\": $fa-var-arrow-left-rotate,\n \"arrow-rotate-back\": $fa-var-arrow-rotate-back,\n \"arrow-rotate-backward\": $fa-var-arrow-rotate-backward,\n \"undo\": $fa-var-undo,\n \"hard-drive\": $fa-var-hard-drive,\n \"hdd\": $fa-var-hdd,\n \"face-grin-squint-tears\": $fa-var-face-grin-squint-tears,\n \"grin-squint-tears\": $fa-var-grin-squint-tears,\n \"dumbbell\": $fa-var-dumbbell,\n \"rectangle-list\": $fa-var-rectangle-list,\n \"list-alt\": $fa-var-list-alt,\n \"tarp-droplet\": $fa-var-tarp-droplet,\n \"house-medical-circle-check\": $fa-var-house-medical-circle-check,\n \"person-skiing-nordic\": $fa-var-person-skiing-nordic,\n \"skiing-nordic\": $fa-var-skiing-nordic,\n \"calendar-plus\": $fa-var-calendar-plus,\n \"plane-arrival\": $fa-var-plane-arrival,\n \"circle-left\": $fa-var-circle-left,\n \"arrow-alt-circle-left\": $fa-var-arrow-alt-circle-left,\n \"train-subway\": $fa-var-train-subway,\n \"subway\": $fa-var-subway,\n \"chart-gantt\": $fa-var-chart-gantt,\n \"indian-rupee-sign\": $fa-var-indian-rupee-sign,\n \"indian-rupee\": $fa-var-indian-rupee,\n \"inr\": $fa-var-inr,\n \"crop-simple\": $fa-var-crop-simple,\n \"crop-alt\": $fa-var-crop-alt,\n \"money-bill-1\": $fa-var-money-bill-1,\n \"money-bill-alt\": $fa-var-money-bill-alt,\n \"left-long\": $fa-var-left-long,\n \"long-arrow-alt-left\": $fa-var-long-arrow-alt-left,\n \"dna\": $fa-var-dna,\n \"virus-slash\": $fa-var-virus-slash,\n \"minus\": $fa-var-minus,\n \"subtract\": $fa-var-subtract,\n \"chess\": $fa-var-chess,\n \"arrow-left-long\": $fa-var-arrow-left-long,\n \"long-arrow-left\": $fa-var-long-arrow-left,\n \"plug-circle-check\": $fa-var-plug-circle-check,\n \"street-view\": $fa-var-street-view,\n \"franc-sign\": $fa-var-franc-sign,\n \"volume-off\": $fa-var-volume-off,\n \"hands-asl-interpreting\": $fa-var-hands-asl-interpreting,\n \"american-sign-language-interpreting\": $fa-var-american-sign-language-interpreting,\n \"asl-interpreting\": $fa-var-asl-interpreting,\n \"hands-american-sign-language-interpreting\": $fa-var-hands-american-sign-language-interpreting,\n \"gear\": $fa-var-gear,\n \"cog\": $fa-var-cog,\n \"droplet-slash\": $fa-var-droplet-slash,\n \"tint-slash\": $fa-var-tint-slash,\n \"mosque\": $fa-var-mosque,\n \"mosquito\": $fa-var-mosquito,\n \"star-of-david\": $fa-var-star-of-david,\n \"person-military-rifle\": $fa-var-person-military-rifle,\n \"cart-shopping\": $fa-var-cart-shopping,\n \"shopping-cart\": $fa-var-shopping-cart,\n \"vials\": $fa-var-vials,\n \"plug-circle-plus\": $fa-var-plug-circle-plus,\n \"place-of-worship\": $fa-var-place-of-worship,\n \"grip-vertical\": $fa-var-grip-vertical,\n \"hexagon-nodes\": $fa-var-hexagon-nodes,\n \"arrow-turn-up\": $fa-var-arrow-turn-up,\n \"level-up\": $fa-var-level-up,\n \"u\": $fa-var-u,\n \"square-root-variable\": $fa-var-square-root-variable,\n \"square-root-alt\": $fa-var-square-root-alt,\n \"clock\": $fa-var-clock,\n \"clock-four\": $fa-var-clock-four,\n \"backward-step\": $fa-var-backward-step,\n \"step-backward\": $fa-var-step-backward,\n \"pallet\": $fa-var-pallet,\n \"faucet\": $fa-var-faucet,\n \"baseball-bat-ball\": $fa-var-baseball-bat-ball,\n \"s\": $fa-var-s,\n \"timeline\": $fa-var-timeline,\n \"keyboard\": $fa-var-keyboard,\n \"caret-down\": $fa-var-caret-down,\n \"house-chimney-medical\": $fa-var-house-chimney-medical,\n \"clinic-medical\": $fa-var-clinic-medical,\n \"temperature-three-quarters\": $fa-var-temperature-three-quarters,\n \"temperature-3\": $fa-var-temperature-3,\n \"thermometer-3\": $fa-var-thermometer-3,\n \"thermometer-three-quarters\": $fa-var-thermometer-three-quarters,\n \"mobile-screen\": $fa-var-mobile-screen,\n \"mobile-android-alt\": $fa-var-mobile-android-alt,\n \"plane-up\": $fa-var-plane-up,\n \"piggy-bank\": $fa-var-piggy-bank,\n \"battery-half\": $fa-var-battery-half,\n \"battery-3\": $fa-var-battery-3,\n \"mountain-city\": $fa-var-mountain-city,\n \"coins\": $fa-var-coins,\n \"khanda\": $fa-var-khanda,\n \"sliders\": $fa-var-sliders,\n \"sliders-h\": $fa-var-sliders-h,\n \"folder-tree\": $fa-var-folder-tree,\n \"network-wired\": $fa-var-network-wired,\n \"map-pin\": $fa-var-map-pin,\n \"hamsa\": $fa-var-hamsa,\n \"cent-sign\": $fa-var-cent-sign,\n \"flask\": $fa-var-flask,\n \"person-pregnant\": $fa-var-person-pregnant,\n \"wand-sparkles\": $fa-var-wand-sparkles,\n \"ellipsis-vertical\": $fa-var-ellipsis-vertical,\n \"ellipsis-v\": $fa-var-ellipsis-v,\n \"ticket\": $fa-var-ticket,\n \"power-off\": $fa-var-power-off,\n \"right-long\": $fa-var-right-long,\n \"long-arrow-alt-right\": $fa-var-long-arrow-alt-right,\n \"flag-usa\": $fa-var-flag-usa,\n \"laptop-file\": $fa-var-laptop-file,\n \"tty\": $fa-var-tty,\n \"teletype\": $fa-var-teletype,\n \"diagram-next\": $fa-var-diagram-next,\n \"person-rifle\": $fa-var-person-rifle,\n \"house-medical-circle-exclamation\": $fa-var-house-medical-circle-exclamation,\n \"closed-captioning\": $fa-var-closed-captioning,\n \"person-hiking\": $fa-var-person-hiking,\n \"hiking\": $fa-var-hiking,\n \"venus-double\": $fa-var-venus-double,\n \"images\": $fa-var-images,\n \"calculator\": $fa-var-calculator,\n \"people-pulling\": $fa-var-people-pulling,\n \"n\": $fa-var-n,\n \"cable-car\": $fa-var-cable-car,\n \"tram\": $fa-var-tram,\n \"cloud-rain\": $fa-var-cloud-rain,\n \"building-circle-xmark\": $fa-var-building-circle-xmark,\n \"ship\": $fa-var-ship,\n \"arrows-down-to-line\": $fa-var-arrows-down-to-line,\n \"download\": $fa-var-download,\n \"face-grin\": $fa-var-face-grin,\n \"grin\": $fa-var-grin,\n \"delete-left\": $fa-var-delete-left,\n \"backspace\": $fa-var-backspace,\n \"eye-dropper\": $fa-var-eye-dropper,\n \"eye-dropper-empty\": $fa-var-eye-dropper-empty,\n \"eyedropper\": $fa-var-eyedropper,\n \"file-circle-check\": $fa-var-file-circle-check,\n \"forward\": $fa-var-forward,\n \"mobile\": $fa-var-mobile,\n \"mobile-android\": $fa-var-mobile-android,\n \"mobile-phone\": $fa-var-mobile-phone,\n \"face-meh\": $fa-var-face-meh,\n \"meh\": $fa-var-meh,\n \"align-center\": $fa-var-align-center,\n \"book-skull\": $fa-var-book-skull,\n \"book-dead\": $fa-var-book-dead,\n \"id-card\": $fa-var-id-card,\n \"drivers-license\": $fa-var-drivers-license,\n \"outdent\": $fa-var-outdent,\n \"dedent\": $fa-var-dedent,\n \"heart-circle-exclamation\": $fa-var-heart-circle-exclamation,\n \"house\": $fa-var-house,\n \"home\": $fa-var-home,\n \"home-alt\": $fa-var-home-alt,\n \"home-lg-alt\": $fa-var-home-lg-alt,\n \"calendar-week\": $fa-var-calendar-week,\n \"laptop-medical\": $fa-var-laptop-medical,\n \"b\": $fa-var-b,\n \"file-medical\": $fa-var-file-medical,\n \"dice-one\": $fa-var-dice-one,\n \"kiwi-bird\": $fa-var-kiwi-bird,\n \"arrow-right-arrow-left\": $fa-var-arrow-right-arrow-left,\n \"exchange\": $fa-var-exchange,\n \"rotate-right\": $fa-var-rotate-right,\n \"redo-alt\": $fa-var-redo-alt,\n \"rotate-forward\": $fa-var-rotate-forward,\n \"utensils\": $fa-var-utensils,\n \"cutlery\": $fa-var-cutlery,\n \"arrow-up-wide-short\": $fa-var-arrow-up-wide-short,\n \"sort-amount-up\": $fa-var-sort-amount-up,\n \"mill-sign\": $fa-var-mill-sign,\n \"bowl-rice\": $fa-var-bowl-rice,\n \"skull\": $fa-var-skull,\n \"tower-broadcast\": $fa-var-tower-broadcast,\n \"broadcast-tower\": $fa-var-broadcast-tower,\n \"truck-pickup\": $fa-var-truck-pickup,\n \"up-long\": $fa-var-up-long,\n \"long-arrow-alt-up\": $fa-var-long-arrow-alt-up,\n \"stop\": $fa-var-stop,\n \"code-merge\": $fa-var-code-merge,\n \"upload\": $fa-var-upload,\n \"hurricane\": $fa-var-hurricane,\n \"mound\": $fa-var-mound,\n \"toilet-portable\": $fa-var-toilet-portable,\n \"compact-disc\": $fa-var-compact-disc,\n \"file-arrow-down\": $fa-var-file-arrow-down,\n \"file-download\": $fa-var-file-download,\n \"caravan\": $fa-var-caravan,\n \"shield-cat\": $fa-var-shield-cat,\n \"bolt\": $fa-var-bolt,\n \"zap\": $fa-var-zap,\n \"glass-water\": $fa-var-glass-water,\n \"oil-well\": $fa-var-oil-well,\n \"vault\": $fa-var-vault,\n \"mars\": $fa-var-mars,\n \"toilet\": $fa-var-toilet,\n \"plane-circle-xmark\": $fa-var-plane-circle-xmark,\n \"yen-sign\": $fa-var-yen-sign,\n \"cny\": $fa-var-cny,\n \"jpy\": $fa-var-jpy,\n \"rmb\": $fa-var-rmb,\n \"yen\": $fa-var-yen,\n \"ruble-sign\": $fa-var-ruble-sign,\n \"rouble\": $fa-var-rouble,\n \"rub\": $fa-var-rub,\n \"ruble\": $fa-var-ruble,\n \"sun\": $fa-var-sun,\n \"guitar\": $fa-var-guitar,\n \"face-laugh-wink\": $fa-var-face-laugh-wink,\n \"laugh-wink\": $fa-var-laugh-wink,\n \"horse-head\": $fa-var-horse-head,\n \"bore-hole\": $fa-var-bore-hole,\n \"industry\": $fa-var-industry,\n \"circle-down\": $fa-var-circle-down,\n \"arrow-alt-circle-down\": $fa-var-arrow-alt-circle-down,\n \"arrows-turn-to-dots\": $fa-var-arrows-turn-to-dots,\n \"florin-sign\": $fa-var-florin-sign,\n \"arrow-down-short-wide\": $fa-var-arrow-down-short-wide,\n \"sort-amount-desc\": $fa-var-sort-amount-desc,\n \"sort-amount-down-alt\": $fa-var-sort-amount-down-alt,\n \"less-than\": $fa-var-less-than,\n \"angle-down\": $fa-var-angle-down,\n \"car-tunnel\": $fa-var-car-tunnel,\n \"head-side-cough\": $fa-var-head-side-cough,\n \"grip-lines\": $fa-var-grip-lines,\n \"thumbs-down\": $fa-var-thumbs-down,\n \"user-lock\": $fa-var-user-lock,\n \"arrow-right-long\": $fa-var-arrow-right-long,\n \"long-arrow-right\": $fa-var-long-arrow-right,\n \"anchor-circle-xmark\": $fa-var-anchor-circle-xmark,\n \"ellipsis\": $fa-var-ellipsis,\n \"ellipsis-h\": $fa-var-ellipsis-h,\n \"chess-pawn\": $fa-var-chess-pawn,\n \"kit-medical\": $fa-var-kit-medical,\n \"first-aid\": $fa-var-first-aid,\n \"person-through-window\": $fa-var-person-through-window,\n \"toolbox\": $fa-var-toolbox,\n \"hands-holding-circle\": $fa-var-hands-holding-circle,\n \"bug\": $fa-var-bug,\n \"credit-card\": $fa-var-credit-card,\n \"credit-card-alt\": $fa-var-credit-card-alt,\n \"car\": $fa-var-car,\n \"automobile\": $fa-var-automobile,\n \"hand-holding-hand\": $fa-var-hand-holding-hand,\n \"book-open-reader\": $fa-var-book-open-reader,\n \"book-reader\": $fa-var-book-reader,\n \"mountain-sun\": $fa-var-mountain-sun,\n \"arrows-left-right-to-line\": $fa-var-arrows-left-right-to-line,\n \"dice-d20\": $fa-var-dice-d20,\n \"truck-droplet\": $fa-var-truck-droplet,\n \"file-circle-xmark\": $fa-var-file-circle-xmark,\n \"temperature-arrow-up\": $fa-var-temperature-arrow-up,\n \"temperature-up\": $fa-var-temperature-up,\n \"medal\": $fa-var-medal,\n \"bed\": $fa-var-bed,\n \"square-h\": $fa-var-square-h,\n \"h-square\": $fa-var-h-square,\n \"podcast\": $fa-var-podcast,\n \"temperature-full\": $fa-var-temperature-full,\n \"temperature-4\": $fa-var-temperature-4,\n \"thermometer-4\": $fa-var-thermometer-4,\n \"thermometer-full\": $fa-var-thermometer-full,\n \"bell\": $fa-var-bell,\n \"superscript\": $fa-var-superscript,\n \"plug-circle-xmark\": $fa-var-plug-circle-xmark,\n \"star-of-life\": $fa-var-star-of-life,\n \"phone-slash\": $fa-var-phone-slash,\n \"paint-roller\": $fa-var-paint-roller,\n \"handshake-angle\": $fa-var-handshake-angle,\n \"hands-helping\": $fa-var-hands-helping,\n \"location-dot\": $fa-var-location-dot,\n \"map-marker-alt\": $fa-var-map-marker-alt,\n \"file\": $fa-var-file,\n \"greater-than\": $fa-var-greater-than,\n \"person-swimming\": $fa-var-person-swimming,\n \"swimmer\": $fa-var-swimmer,\n \"arrow-down\": $fa-var-arrow-down,\n \"droplet\": $fa-var-droplet,\n \"tint\": $fa-var-tint,\n \"eraser\": $fa-var-eraser,\n \"earth-americas\": $fa-var-earth-americas,\n \"earth\": $fa-var-earth,\n \"earth-america\": $fa-var-earth-america,\n \"globe-americas\": $fa-var-globe-americas,\n \"person-burst\": $fa-var-person-burst,\n \"dove\": $fa-var-dove,\n \"battery-empty\": $fa-var-battery-empty,\n \"battery-0\": $fa-var-battery-0,\n \"socks\": $fa-var-socks,\n \"inbox\": $fa-var-inbox,\n \"section\": $fa-var-section,\n \"gauge-high\": $fa-var-gauge-high,\n \"tachometer-alt\": $fa-var-tachometer-alt,\n \"tachometer-alt-fast\": $fa-var-tachometer-alt-fast,\n \"envelope-open-text\": $fa-var-envelope-open-text,\n \"hospital\": $fa-var-hospital,\n \"hospital-alt\": $fa-var-hospital-alt,\n \"hospital-wide\": $fa-var-hospital-wide,\n \"wine-bottle\": $fa-var-wine-bottle,\n \"chess-rook\": $fa-var-chess-rook,\n \"bars-staggered\": $fa-var-bars-staggered,\n \"reorder\": $fa-var-reorder,\n \"stream\": $fa-var-stream,\n \"dharmachakra\": $fa-var-dharmachakra,\n \"hotdog\": $fa-var-hotdog,\n \"person-walking-with-cane\": $fa-var-person-walking-with-cane,\n \"blind\": $fa-var-blind,\n \"drum\": $fa-var-drum,\n \"ice-cream\": $fa-var-ice-cream,\n \"heart-circle-bolt\": $fa-var-heart-circle-bolt,\n \"fax\": $fa-var-fax,\n \"paragraph\": $fa-var-paragraph,\n \"check-to-slot\": $fa-var-check-to-slot,\n \"vote-yea\": $fa-var-vote-yea,\n \"star-half\": $fa-var-star-half,\n \"boxes-stacked\": $fa-var-boxes-stacked,\n \"boxes\": $fa-var-boxes,\n \"boxes-alt\": $fa-var-boxes-alt,\n \"link\": $fa-var-link,\n \"chain\": $fa-var-chain,\n \"ear-listen\": $fa-var-ear-listen,\n \"assistive-listening-systems\": $fa-var-assistive-listening-systems,\n \"tree-city\": $fa-var-tree-city,\n \"play\": $fa-var-play,\n \"font\": $fa-var-font,\n \"table-cells-row-lock\": $fa-var-table-cells-row-lock,\n \"rupiah-sign\": $fa-var-rupiah-sign,\n \"magnifying-glass\": $fa-var-magnifying-glass,\n \"search\": $fa-var-search,\n \"table-tennis-paddle-ball\": $fa-var-table-tennis-paddle-ball,\n \"ping-pong-paddle-ball\": $fa-var-ping-pong-paddle-ball,\n \"table-tennis\": $fa-var-table-tennis,\n \"person-dots-from-line\": $fa-var-person-dots-from-line,\n \"diagnoses\": $fa-var-diagnoses,\n \"trash-can-arrow-up\": $fa-var-trash-can-arrow-up,\n \"trash-restore-alt\": $fa-var-trash-restore-alt,\n \"naira-sign\": $fa-var-naira-sign,\n \"cart-arrow-down\": $fa-var-cart-arrow-down,\n \"walkie-talkie\": $fa-var-walkie-talkie,\n \"file-pen\": $fa-var-file-pen,\n \"file-edit\": $fa-var-file-edit,\n \"receipt\": $fa-var-receipt,\n \"square-pen\": $fa-var-square-pen,\n \"pen-square\": $fa-var-pen-square,\n \"pencil-square\": $fa-var-pencil-square,\n \"suitcase-rolling\": $fa-var-suitcase-rolling,\n \"person-circle-exclamation\": $fa-var-person-circle-exclamation,\n \"chevron-down\": $fa-var-chevron-down,\n \"battery-full\": $fa-var-battery-full,\n \"battery\": $fa-var-battery,\n \"battery-5\": $fa-var-battery-5,\n \"skull-crossbones\": $fa-var-skull-crossbones,\n \"code-compare\": $fa-var-code-compare,\n \"list-ul\": $fa-var-list-ul,\n \"list-dots\": $fa-var-list-dots,\n \"school-lock\": $fa-var-school-lock,\n \"tower-cell\": $fa-var-tower-cell,\n \"down-long\": $fa-var-down-long,\n \"long-arrow-alt-down\": $fa-var-long-arrow-alt-down,\n \"ranking-star\": $fa-var-ranking-star,\n \"chess-king\": $fa-var-chess-king,\n \"person-harassing\": $fa-var-person-harassing,\n \"brazilian-real-sign\": $fa-var-brazilian-real-sign,\n \"landmark-dome\": $fa-var-landmark-dome,\n \"landmark-alt\": $fa-var-landmark-alt,\n \"arrow-up\": $fa-var-arrow-up,\n \"tv\": $fa-var-tv,\n \"television\": $fa-var-television,\n \"tv-alt\": $fa-var-tv-alt,\n \"shrimp\": $fa-var-shrimp,\n \"list-check\": $fa-var-list-check,\n \"tasks\": $fa-var-tasks,\n \"jug-detergent\": $fa-var-jug-detergent,\n \"circle-user\": $fa-var-circle-user,\n \"user-circle\": $fa-var-user-circle,\n \"user-shield\": $fa-var-user-shield,\n \"wind\": $fa-var-wind,\n \"car-burst\": $fa-var-car-burst,\n \"car-crash\": $fa-var-car-crash,\n \"y\": $fa-var-y,\n \"person-snowboarding\": $fa-var-person-snowboarding,\n \"snowboarding\": $fa-var-snowboarding,\n \"truck-fast\": $fa-var-truck-fast,\n \"shipping-fast\": $fa-var-shipping-fast,\n \"fish\": $fa-var-fish,\n \"user-graduate\": $fa-var-user-graduate,\n \"circle-half-stroke\": $fa-var-circle-half-stroke,\n \"adjust\": $fa-var-adjust,\n \"clapperboard\": $fa-var-clapperboard,\n \"circle-radiation\": $fa-var-circle-radiation,\n \"radiation-alt\": $fa-var-radiation-alt,\n \"baseball\": $fa-var-baseball,\n \"baseball-ball\": $fa-var-baseball-ball,\n \"jet-fighter-up\": $fa-var-jet-fighter-up,\n \"diagram-project\": $fa-var-diagram-project,\n \"project-diagram\": $fa-var-project-diagram,\n \"copy\": $fa-var-copy,\n \"volume-xmark\": $fa-var-volume-xmark,\n \"volume-mute\": $fa-var-volume-mute,\n \"volume-times\": $fa-var-volume-times,\n \"hand-sparkles\": $fa-var-hand-sparkles,\n \"grip\": $fa-var-grip,\n \"grip-horizontal\": $fa-var-grip-horizontal,\n \"share-from-square\": $fa-var-share-from-square,\n \"share-square\": $fa-var-share-square,\n \"child-combatant\": $fa-var-child-combatant,\n \"child-rifle\": $fa-var-child-rifle,\n \"gun\": $fa-var-gun,\n \"square-phone\": $fa-var-square-phone,\n \"phone-square\": $fa-var-phone-square,\n \"plus\": $fa-var-plus,\n \"add\": $fa-var-add,\n \"expand\": $fa-var-expand,\n \"computer\": $fa-var-computer,\n \"xmark\": $fa-var-xmark,\n \"close\": $fa-var-close,\n \"multiply\": $fa-var-multiply,\n \"remove\": $fa-var-remove,\n \"times\": $fa-var-times,\n \"arrows-up-down-left-right\": $fa-var-arrows-up-down-left-right,\n \"arrows\": $fa-var-arrows,\n \"chalkboard-user\": $fa-var-chalkboard-user,\n \"chalkboard-teacher\": $fa-var-chalkboard-teacher,\n \"peso-sign\": $fa-var-peso-sign,\n \"building-shield\": $fa-var-building-shield,\n \"baby\": $fa-var-baby,\n \"users-line\": $fa-var-users-line,\n \"quote-left\": $fa-var-quote-left,\n \"quote-left-alt\": $fa-var-quote-left-alt,\n \"tractor\": $fa-var-tractor,\n \"trash-arrow-up\": $fa-var-trash-arrow-up,\n \"trash-restore\": $fa-var-trash-restore,\n \"arrow-down-up-lock\": $fa-var-arrow-down-up-lock,\n \"lines-leaning\": $fa-var-lines-leaning,\n \"ruler-combined\": $fa-var-ruler-combined,\n \"copyright\": $fa-var-copyright,\n \"equals\": $fa-var-equals,\n \"blender\": $fa-var-blender,\n \"teeth\": $fa-var-teeth,\n \"shekel-sign\": $fa-var-shekel-sign,\n \"ils\": $fa-var-ils,\n \"shekel\": $fa-var-shekel,\n \"sheqel\": $fa-var-sheqel,\n \"sheqel-sign\": $fa-var-sheqel-sign,\n \"map\": $fa-var-map,\n \"rocket\": $fa-var-rocket,\n \"photo-film\": $fa-var-photo-film,\n \"photo-video\": $fa-var-photo-video,\n \"folder-minus\": $fa-var-folder-minus,\n \"hexagon-nodes-bolt\": $fa-var-hexagon-nodes-bolt,\n \"store\": $fa-var-store,\n \"arrow-trend-up\": $fa-var-arrow-trend-up,\n \"plug-circle-minus\": $fa-var-plug-circle-minus,\n \"sign-hanging\": $fa-var-sign-hanging,\n \"sign\": $fa-var-sign,\n \"bezier-curve\": $fa-var-bezier-curve,\n \"bell-slash\": $fa-var-bell-slash,\n \"tablet\": $fa-var-tablet,\n \"tablet-android\": $fa-var-tablet-android,\n \"school-flag\": $fa-var-school-flag,\n \"fill\": $fa-var-fill,\n \"angle-up\": $fa-var-angle-up,\n \"drumstick-bite\": $fa-var-drumstick-bite,\n \"holly-berry\": $fa-var-holly-berry,\n \"chevron-left\": $fa-var-chevron-left,\n \"bacteria\": $fa-var-bacteria,\n \"hand-lizard\": $fa-var-hand-lizard,\n \"notdef\": $fa-var-notdef,\n \"disease\": $fa-var-disease,\n \"briefcase-medical\": $fa-var-briefcase-medical,\n \"genderless\": $fa-var-genderless,\n \"chevron-right\": $fa-var-chevron-right,\n \"retweet\": $fa-var-retweet,\n \"car-rear\": $fa-var-car-rear,\n \"car-alt\": $fa-var-car-alt,\n \"pump-soap\": $fa-var-pump-soap,\n \"video-slash\": $fa-var-video-slash,\n \"battery-quarter\": $fa-var-battery-quarter,\n \"battery-2\": $fa-var-battery-2,\n \"radio\": $fa-var-radio,\n \"baby-carriage\": $fa-var-baby-carriage,\n \"carriage-baby\": $fa-var-carriage-baby,\n \"traffic-light\": $fa-var-traffic-light,\n \"thermometer\": $fa-var-thermometer,\n \"vr-cardboard\": $fa-var-vr-cardboard,\n \"hand-middle-finger\": $fa-var-hand-middle-finger,\n \"percent\": $fa-var-percent,\n \"percentage\": $fa-var-percentage,\n \"truck-moving\": $fa-var-truck-moving,\n \"glass-water-droplet\": $fa-var-glass-water-droplet,\n \"display\": $fa-var-display,\n \"face-smile\": $fa-var-face-smile,\n \"smile\": $fa-var-smile,\n \"thumbtack\": $fa-var-thumbtack,\n \"thumb-tack\": $fa-var-thumb-tack,\n \"trophy\": $fa-var-trophy,\n \"person-praying\": $fa-var-person-praying,\n \"pray\": $fa-var-pray,\n \"hammer\": $fa-var-hammer,\n \"hand-peace\": $fa-var-hand-peace,\n \"rotate\": $fa-var-rotate,\n \"sync-alt\": $fa-var-sync-alt,\n \"spinner\": $fa-var-spinner,\n \"robot\": $fa-var-robot,\n \"peace\": $fa-var-peace,\n \"gears\": $fa-var-gears,\n \"cogs\": $fa-var-cogs,\n \"warehouse\": $fa-var-warehouse,\n \"arrow-up-right-dots\": $fa-var-arrow-up-right-dots,\n \"splotch\": $fa-var-splotch,\n \"face-grin-hearts\": $fa-var-face-grin-hearts,\n \"grin-hearts\": $fa-var-grin-hearts,\n \"dice-four\": $fa-var-dice-four,\n \"sim-card\": $fa-var-sim-card,\n \"transgender\": $fa-var-transgender,\n \"transgender-alt\": $fa-var-transgender-alt,\n \"mercury\": $fa-var-mercury,\n \"arrow-turn-down\": $fa-var-arrow-turn-down,\n \"level-down\": $fa-var-level-down,\n \"person-falling-burst\": $fa-var-person-falling-burst,\n \"award\": $fa-var-award,\n \"ticket-simple\": $fa-var-ticket-simple,\n \"ticket-alt\": $fa-var-ticket-alt,\n \"building\": $fa-var-building,\n \"angles-left\": $fa-var-angles-left,\n \"angle-double-left\": $fa-var-angle-double-left,\n \"qrcode\": $fa-var-qrcode,\n \"clock-rotate-left\": $fa-var-clock-rotate-left,\n \"history\": $fa-var-history,\n \"face-grin-beam-sweat\": $fa-var-face-grin-beam-sweat,\n \"grin-beam-sweat\": $fa-var-grin-beam-sweat,\n \"file-export\": $fa-var-file-export,\n \"arrow-right-from-file\": $fa-var-arrow-right-from-file,\n \"shield\": $fa-var-shield,\n \"shield-blank\": $fa-var-shield-blank,\n \"arrow-up-short-wide\": $fa-var-arrow-up-short-wide,\n \"sort-amount-up-alt\": $fa-var-sort-amount-up-alt,\n \"comment-nodes\": $fa-var-comment-nodes,\n \"house-medical\": $fa-var-house-medical,\n \"golf-ball-tee\": $fa-var-golf-ball-tee,\n \"golf-ball\": $fa-var-golf-ball,\n \"circle-chevron-left\": $fa-var-circle-chevron-left,\n \"chevron-circle-left\": $fa-var-chevron-circle-left,\n \"house-chimney-window\": $fa-var-house-chimney-window,\n \"pen-nib\": $fa-var-pen-nib,\n \"tent-arrow-turn-left\": $fa-var-tent-arrow-turn-left,\n \"tents\": $fa-var-tents,\n \"wand-magic\": $fa-var-wand-magic,\n \"magic\": $fa-var-magic,\n \"dog\": $fa-var-dog,\n \"carrot\": $fa-var-carrot,\n \"moon\": $fa-var-moon,\n \"wine-glass-empty\": $fa-var-wine-glass-empty,\n \"wine-glass-alt\": $fa-var-wine-glass-alt,\n \"cheese\": $fa-var-cheese,\n \"yin-yang\": $fa-var-yin-yang,\n \"music\": $fa-var-music,\n \"code-commit\": $fa-var-code-commit,\n \"temperature-low\": $fa-var-temperature-low,\n \"person-biking\": $fa-var-person-biking,\n \"biking\": $fa-var-biking,\n \"broom\": $fa-var-broom,\n \"shield-heart\": $fa-var-shield-heart,\n \"gopuram\": $fa-var-gopuram,\n \"earth-oceania\": $fa-var-earth-oceania,\n \"globe-oceania\": $fa-var-globe-oceania,\n \"square-xmark\": $fa-var-square-xmark,\n \"times-square\": $fa-var-times-square,\n \"xmark-square\": $fa-var-xmark-square,\n \"hashtag\": $fa-var-hashtag,\n \"up-right-and-down-left-from-center\": $fa-var-up-right-and-down-left-from-center,\n \"expand-alt\": $fa-var-expand-alt,\n \"oil-can\": $fa-var-oil-can,\n \"t\": $fa-var-t,\n \"hippo\": $fa-var-hippo,\n \"chart-column\": $fa-var-chart-column,\n \"infinity\": $fa-var-infinity,\n \"vial-circle-check\": $fa-var-vial-circle-check,\n \"person-arrow-down-to-line\": $fa-var-person-arrow-down-to-line,\n \"voicemail\": $fa-var-voicemail,\n \"fan\": $fa-var-fan,\n \"person-walking-luggage\": $fa-var-person-walking-luggage,\n \"up-down\": $fa-var-up-down,\n \"arrows-alt-v\": $fa-var-arrows-alt-v,\n \"cloud-moon-rain\": $fa-var-cloud-moon-rain,\n \"calendar\": $fa-var-calendar,\n \"trailer\": $fa-var-trailer,\n \"bahai\": $fa-var-bahai,\n \"haykal\": $fa-var-haykal,\n \"sd-card\": $fa-var-sd-card,\n \"dragon\": $fa-var-dragon,\n \"shoe-prints\": $fa-var-shoe-prints,\n \"circle-plus\": $fa-var-circle-plus,\n \"plus-circle\": $fa-var-plus-circle,\n \"face-grin-tongue-wink\": $fa-var-face-grin-tongue-wink,\n \"grin-tongue-wink\": $fa-var-grin-tongue-wink,\n \"hand-holding\": $fa-var-hand-holding,\n \"plug-circle-exclamation\": $fa-var-plug-circle-exclamation,\n \"link-slash\": $fa-var-link-slash,\n \"chain-broken\": $fa-var-chain-broken,\n \"chain-slash\": $fa-var-chain-slash,\n \"unlink\": $fa-var-unlink,\n \"clone\": $fa-var-clone,\n \"person-walking-arrow-loop-left\": $fa-var-person-walking-arrow-loop-left,\n \"arrow-up-z-a\": $fa-var-arrow-up-z-a,\n \"sort-alpha-up-alt\": $fa-var-sort-alpha-up-alt,\n \"fire-flame-curved\": $fa-var-fire-flame-curved,\n \"fire-alt\": $fa-var-fire-alt,\n \"tornado\": $fa-var-tornado,\n \"file-circle-plus\": $fa-var-file-circle-plus,\n \"book-quran\": $fa-var-book-quran,\n \"quran\": $fa-var-quran,\n \"anchor\": $fa-var-anchor,\n \"border-all\": $fa-var-border-all,\n \"face-angry\": $fa-var-face-angry,\n \"angry\": $fa-var-angry,\n \"cookie-bite\": $fa-var-cookie-bite,\n \"arrow-trend-down\": $fa-var-arrow-trend-down,\n \"rss\": $fa-var-rss,\n \"feed\": $fa-var-feed,\n \"draw-polygon\": $fa-var-draw-polygon,\n \"scale-balanced\": $fa-var-scale-balanced,\n \"balance-scale\": $fa-var-balance-scale,\n \"gauge-simple-high\": $fa-var-gauge-simple-high,\n \"tachometer\": $fa-var-tachometer,\n \"tachometer-fast\": $fa-var-tachometer-fast,\n \"shower\": $fa-var-shower,\n \"desktop\": $fa-var-desktop,\n \"desktop-alt\": $fa-var-desktop-alt,\n \"m\": $fa-var-m,\n \"table-list\": $fa-var-table-list,\n \"th-list\": $fa-var-th-list,\n \"comment-sms\": $fa-var-comment-sms,\n \"sms\": $fa-var-sms,\n \"book\": $fa-var-book,\n \"user-plus\": $fa-var-user-plus,\n \"check\": $fa-var-check,\n \"battery-three-quarters\": $fa-var-battery-three-quarters,\n \"battery-4\": $fa-var-battery-4,\n \"house-circle-check\": $fa-var-house-circle-check,\n \"angle-left\": $fa-var-angle-left,\n \"diagram-successor\": $fa-var-diagram-successor,\n \"truck-arrow-right\": $fa-var-truck-arrow-right,\n \"arrows-split-up-and-left\": $fa-var-arrows-split-up-and-left,\n \"hand-fist\": $fa-var-hand-fist,\n \"fist-raised\": $fa-var-fist-raised,\n \"cloud-moon\": $fa-var-cloud-moon,\n \"briefcase\": $fa-var-briefcase,\n \"person-falling\": $fa-var-person-falling,\n \"image-portrait\": $fa-var-image-portrait,\n \"portrait\": $fa-var-portrait,\n \"user-tag\": $fa-var-user-tag,\n \"rug\": $fa-var-rug,\n \"earth-europe\": $fa-var-earth-europe,\n \"globe-europe\": $fa-var-globe-europe,\n \"cart-flatbed-suitcase\": $fa-var-cart-flatbed-suitcase,\n \"luggage-cart\": $fa-var-luggage-cart,\n \"rectangle-xmark\": $fa-var-rectangle-xmark,\n \"rectangle-times\": $fa-var-rectangle-times,\n \"times-rectangle\": $fa-var-times-rectangle,\n \"window-close\": $fa-var-window-close,\n \"baht-sign\": $fa-var-baht-sign,\n \"book-open\": $fa-var-book-open,\n \"book-journal-whills\": $fa-var-book-journal-whills,\n \"journal-whills\": $fa-var-journal-whills,\n \"handcuffs\": $fa-var-handcuffs,\n \"triangle-exclamation\": $fa-var-triangle-exclamation,\n \"exclamation-triangle\": $fa-var-exclamation-triangle,\n \"warning\": $fa-var-warning,\n \"database\": $fa-var-database,\n \"share\": $fa-var-share,\n \"mail-forward\": $fa-var-mail-forward,\n \"bottle-droplet\": $fa-var-bottle-droplet,\n \"mask-face\": $fa-var-mask-face,\n \"hill-rockslide\": $fa-var-hill-rockslide,\n \"right-left\": $fa-var-right-left,\n \"exchange-alt\": $fa-var-exchange-alt,\n \"paper-plane\": $fa-var-paper-plane,\n \"road-circle-exclamation\": $fa-var-road-circle-exclamation,\n \"dungeon\": $fa-var-dungeon,\n \"align-right\": $fa-var-align-right,\n \"money-bill-1-wave\": $fa-var-money-bill-1-wave,\n \"money-bill-wave-alt\": $fa-var-money-bill-wave-alt,\n \"life-ring\": $fa-var-life-ring,\n \"hands\": $fa-var-hands,\n \"sign-language\": $fa-var-sign-language,\n \"signing\": $fa-var-signing,\n \"calendar-day\": $fa-var-calendar-day,\n \"water-ladder\": $fa-var-water-ladder,\n \"ladder-water\": $fa-var-ladder-water,\n \"swimming-pool\": $fa-var-swimming-pool,\n \"arrows-up-down\": $fa-var-arrows-up-down,\n \"arrows-v\": $fa-var-arrows-v,\n \"face-grimace\": $fa-var-face-grimace,\n \"grimace\": $fa-var-grimace,\n \"wheelchair-move\": $fa-var-wheelchair-move,\n \"wheelchair-alt\": $fa-var-wheelchair-alt,\n \"turn-down\": $fa-var-turn-down,\n \"level-down-alt\": $fa-var-level-down-alt,\n \"person-walking-arrow-right\": $fa-var-person-walking-arrow-right,\n \"square-envelope\": $fa-var-square-envelope,\n \"envelope-square\": $fa-var-envelope-square,\n \"dice\": $fa-var-dice,\n \"bowling-ball\": $fa-var-bowling-ball,\n \"brain\": $fa-var-brain,\n \"bandage\": $fa-var-bandage,\n \"band-aid\": $fa-var-band-aid,\n \"calendar-minus\": $fa-var-calendar-minus,\n \"circle-xmark\": $fa-var-circle-xmark,\n \"times-circle\": $fa-var-times-circle,\n \"xmark-circle\": $fa-var-xmark-circle,\n \"gifts\": $fa-var-gifts,\n \"hotel\": $fa-var-hotel,\n \"earth-asia\": $fa-var-earth-asia,\n \"globe-asia\": $fa-var-globe-asia,\n \"id-card-clip\": $fa-var-id-card-clip,\n \"id-card-alt\": $fa-var-id-card-alt,\n \"magnifying-glass-plus\": $fa-var-magnifying-glass-plus,\n \"search-plus\": $fa-var-search-plus,\n \"thumbs-up\": $fa-var-thumbs-up,\n \"user-clock\": $fa-var-user-clock,\n \"hand-dots\": $fa-var-hand-dots,\n \"allergies\": $fa-var-allergies,\n \"file-invoice\": $fa-var-file-invoice,\n \"window-minimize\": $fa-var-window-minimize,\n \"mug-saucer\": $fa-var-mug-saucer,\n \"coffee\": $fa-var-coffee,\n \"brush\": $fa-var-brush,\n \"file-half-dashed\": $fa-var-file-half-dashed,\n \"mask\": $fa-var-mask,\n \"magnifying-glass-minus\": $fa-var-magnifying-glass-minus,\n \"search-minus\": $fa-var-search-minus,\n \"ruler-vertical\": $fa-var-ruler-vertical,\n \"user-large\": $fa-var-user-large,\n \"user-alt\": $fa-var-user-alt,\n \"train-tram\": $fa-var-train-tram,\n \"user-nurse\": $fa-var-user-nurse,\n \"syringe\": $fa-var-syringe,\n \"cloud-sun\": $fa-var-cloud-sun,\n \"stopwatch-20\": $fa-var-stopwatch-20,\n \"square-full\": $fa-var-square-full,\n \"magnet\": $fa-var-magnet,\n \"jar\": $fa-var-jar,\n \"note-sticky\": $fa-var-note-sticky,\n \"sticky-note\": $fa-var-sticky-note,\n \"bug-slash\": $fa-var-bug-slash,\n \"arrow-up-from-water-pump\": $fa-var-arrow-up-from-water-pump,\n \"bone\": $fa-var-bone,\n \"table-cells-row-unlock\": $fa-var-table-cells-row-unlock,\n \"user-injured\": $fa-var-user-injured,\n \"face-sad-tear\": $fa-var-face-sad-tear,\n \"sad-tear\": $fa-var-sad-tear,\n \"plane\": $fa-var-plane,\n \"tent-arrows-down\": $fa-var-tent-arrows-down,\n \"exclamation\": $fa-var-exclamation,\n \"arrows-spin\": $fa-var-arrows-spin,\n \"print\": $fa-var-print,\n \"turkish-lira-sign\": $fa-var-turkish-lira-sign,\n \"try\": $fa-var-try,\n \"turkish-lira\": $fa-var-turkish-lira,\n \"dollar-sign\": $fa-var-dollar-sign,\n \"dollar\": $fa-var-dollar,\n \"usd\": $fa-var-usd,\n \"x\": $fa-var-x,\n \"magnifying-glass-dollar\": $fa-var-magnifying-glass-dollar,\n \"search-dollar\": $fa-var-search-dollar,\n \"users-gear\": $fa-var-users-gear,\n \"users-cog\": $fa-var-users-cog,\n \"person-military-pointing\": $fa-var-person-military-pointing,\n \"building-columns\": $fa-var-building-columns,\n \"bank\": $fa-var-bank,\n \"institution\": $fa-var-institution,\n \"museum\": $fa-var-museum,\n \"university\": $fa-var-university,\n \"umbrella\": $fa-var-umbrella,\n \"trowel\": $fa-var-trowel,\n \"d\": $fa-var-d,\n \"stapler\": $fa-var-stapler,\n \"masks-theater\": $fa-var-masks-theater,\n \"theater-masks\": $fa-var-theater-masks,\n \"kip-sign\": $fa-var-kip-sign,\n \"hand-point-left\": $fa-var-hand-point-left,\n \"handshake-simple\": $fa-var-handshake-simple,\n \"handshake-alt\": $fa-var-handshake-alt,\n \"jet-fighter\": $fa-var-jet-fighter,\n \"fighter-jet\": $fa-var-fighter-jet,\n \"square-share-nodes\": $fa-var-square-share-nodes,\n \"share-alt-square\": $fa-var-share-alt-square,\n \"barcode\": $fa-var-barcode,\n \"plus-minus\": $fa-var-plus-minus,\n \"video\": $fa-var-video,\n \"video-camera\": $fa-var-video-camera,\n \"graduation-cap\": $fa-var-graduation-cap,\n \"mortar-board\": $fa-var-mortar-board,\n \"hand-holding-medical\": $fa-var-hand-holding-medical,\n \"person-circle-check\": $fa-var-person-circle-check,\n \"turn-up\": $fa-var-turn-up,\n \"level-up-alt\": $fa-var-level-up-alt,\n);\n\n$fa-brand-icons: (\n \"monero\": $fa-var-monero,\n \"hooli\": $fa-var-hooli,\n \"yelp\": $fa-var-yelp,\n \"cc-visa\": $fa-var-cc-visa,\n \"lastfm\": $fa-var-lastfm,\n \"shopware\": $fa-var-shopware,\n \"creative-commons-nc\": $fa-var-creative-commons-nc,\n \"aws\": $fa-var-aws,\n \"redhat\": $fa-var-redhat,\n \"yoast\": $fa-var-yoast,\n \"cloudflare\": $fa-var-cloudflare,\n \"ups\": $fa-var-ups,\n \"pixiv\": $fa-var-pixiv,\n \"wpexplorer\": $fa-var-wpexplorer,\n \"dyalog\": $fa-var-dyalog,\n \"bity\": $fa-var-bity,\n \"stackpath\": $fa-var-stackpath,\n \"buysellads\": $fa-var-buysellads,\n \"first-order\": $fa-var-first-order,\n \"modx\": $fa-var-modx,\n \"guilded\": $fa-var-guilded,\n \"vnv\": $fa-var-vnv,\n \"square-js\": $fa-var-square-js,\n \"js-square\": $fa-var-js-square,\n \"microsoft\": $fa-var-microsoft,\n \"qq\": $fa-var-qq,\n \"orcid\": $fa-var-orcid,\n \"java\": $fa-var-java,\n \"invision\": $fa-var-invision,\n \"creative-commons-pd-alt\": $fa-var-creative-commons-pd-alt,\n \"centercode\": $fa-var-centercode,\n \"glide-g\": $fa-var-glide-g,\n \"drupal\": $fa-var-drupal,\n \"jxl\": $fa-var-jxl,\n \"dart-lang\": $fa-var-dart-lang,\n \"hire-a-helper\": $fa-var-hire-a-helper,\n \"creative-commons-by\": $fa-var-creative-commons-by,\n \"unity\": $fa-var-unity,\n \"whmcs\": $fa-var-whmcs,\n \"rocketchat\": $fa-var-rocketchat,\n \"vk\": $fa-var-vk,\n \"untappd\": $fa-var-untappd,\n \"mailchimp\": $fa-var-mailchimp,\n \"css3-alt\": $fa-var-css3-alt,\n \"square-reddit\": $fa-var-square-reddit,\n \"reddit-square\": $fa-var-reddit-square,\n \"vimeo-v\": $fa-var-vimeo-v,\n \"contao\": $fa-var-contao,\n \"square-font-awesome\": $fa-var-square-font-awesome,\n \"deskpro\": $fa-var-deskpro,\n \"brave\": $fa-var-brave,\n \"sistrix\": $fa-var-sistrix,\n \"square-instagram\": $fa-var-square-instagram,\n \"instagram-square\": $fa-var-instagram-square,\n \"battle-net\": $fa-var-battle-net,\n \"the-red-yeti\": $fa-var-the-red-yeti,\n \"square-hacker-news\": $fa-var-square-hacker-news,\n \"hacker-news-square\": $fa-var-hacker-news-square,\n \"edge\": $fa-var-edge,\n \"threads\": $fa-var-threads,\n \"napster\": $fa-var-napster,\n \"square-snapchat\": $fa-var-square-snapchat,\n \"snapchat-square\": $fa-var-snapchat-square,\n \"google-plus-g\": $fa-var-google-plus-g,\n \"artstation\": $fa-var-artstation,\n \"markdown\": $fa-var-markdown,\n \"sourcetree\": $fa-var-sourcetree,\n \"google-plus\": $fa-var-google-plus,\n \"diaspora\": $fa-var-diaspora,\n \"foursquare\": $fa-var-foursquare,\n \"stack-overflow\": $fa-var-stack-overflow,\n \"github-alt\": $fa-var-github-alt,\n \"phoenix-squadron\": $fa-var-phoenix-squadron,\n \"pagelines\": $fa-var-pagelines,\n \"algolia\": $fa-var-algolia,\n \"red-river\": $fa-var-red-river,\n \"creative-commons-sa\": $fa-var-creative-commons-sa,\n \"safari\": $fa-var-safari,\n \"google\": $fa-var-google,\n \"square-font-awesome-stroke\": $fa-var-square-font-awesome-stroke,\n \"font-awesome-alt\": $fa-var-font-awesome-alt,\n \"atlassian\": $fa-var-atlassian,\n \"linkedin-in\": $fa-var-linkedin-in,\n \"digital-ocean\": $fa-var-digital-ocean,\n \"nimblr\": $fa-var-nimblr,\n \"chromecast\": $fa-var-chromecast,\n \"evernote\": $fa-var-evernote,\n \"hacker-news\": $fa-var-hacker-news,\n \"creative-commons-sampling\": $fa-var-creative-commons-sampling,\n \"adversal\": $fa-var-adversal,\n \"creative-commons\": $fa-var-creative-commons,\n \"watchman-monitoring\": $fa-var-watchman-monitoring,\n \"fonticons\": $fa-var-fonticons,\n \"weixin\": $fa-var-weixin,\n \"shirtsinbulk\": $fa-var-shirtsinbulk,\n \"codepen\": $fa-var-codepen,\n \"git-alt\": $fa-var-git-alt,\n \"lyft\": $fa-var-lyft,\n \"rev\": $fa-var-rev,\n \"windows\": $fa-var-windows,\n \"wizards-of-the-coast\": $fa-var-wizards-of-the-coast,\n \"square-viadeo\": $fa-var-square-viadeo,\n \"viadeo-square\": $fa-var-viadeo-square,\n \"meetup\": $fa-var-meetup,\n \"centos\": $fa-var-centos,\n \"adn\": $fa-var-adn,\n \"cloudsmith\": $fa-var-cloudsmith,\n \"opensuse\": $fa-var-opensuse,\n \"pied-piper-alt\": $fa-var-pied-piper-alt,\n \"square-dribbble\": $fa-var-square-dribbble,\n \"dribbble-square\": $fa-var-dribbble-square,\n \"codiepie\": $fa-var-codiepie,\n \"node\": $fa-var-node,\n \"mix\": $fa-var-mix,\n \"steam\": $fa-var-steam,\n \"cc-apple-pay\": $fa-var-cc-apple-pay,\n \"scribd\": $fa-var-scribd,\n \"debian\": $fa-var-debian,\n \"openid\": $fa-var-openid,\n \"instalod\": $fa-var-instalod,\n \"files-pinwheel\": $fa-var-files-pinwheel,\n \"expeditedssl\": $fa-var-expeditedssl,\n \"sellcast\": $fa-var-sellcast,\n \"square-twitter\": $fa-var-square-twitter,\n \"twitter-square\": $fa-var-twitter-square,\n \"r-project\": $fa-var-r-project,\n \"delicious\": $fa-var-delicious,\n \"freebsd\": $fa-var-freebsd,\n \"vuejs\": $fa-var-vuejs,\n \"accusoft\": $fa-var-accusoft,\n \"ioxhost\": $fa-var-ioxhost,\n \"fonticons-fi\": $fa-var-fonticons-fi,\n \"app-store\": $fa-var-app-store,\n \"cc-mastercard\": $fa-var-cc-mastercard,\n \"itunes-note\": $fa-var-itunes-note,\n \"golang\": $fa-var-golang,\n \"kickstarter\": $fa-var-kickstarter,\n \"square-kickstarter\": $fa-var-square-kickstarter,\n \"grav\": $fa-var-grav,\n \"weibo\": $fa-var-weibo,\n \"uncharted\": $fa-var-uncharted,\n \"firstdraft\": $fa-var-firstdraft,\n \"square-youtube\": $fa-var-square-youtube,\n \"youtube-square\": $fa-var-youtube-square,\n \"wikipedia-w\": $fa-var-wikipedia-w,\n \"wpressr\": $fa-var-wpressr,\n \"rendact\": $fa-var-rendact,\n \"angellist\": $fa-var-angellist,\n \"galactic-republic\": $fa-var-galactic-republic,\n \"nfc-directional\": $fa-var-nfc-directional,\n \"skype\": $fa-var-skype,\n \"joget\": $fa-var-joget,\n \"fedora\": $fa-var-fedora,\n \"stripe-s\": $fa-var-stripe-s,\n \"meta\": $fa-var-meta,\n \"laravel\": $fa-var-laravel,\n \"hotjar\": $fa-var-hotjar,\n \"bluetooth-b\": $fa-var-bluetooth-b,\n \"square-letterboxd\": $fa-var-square-letterboxd,\n \"sticker-mule\": $fa-var-sticker-mule,\n \"creative-commons-zero\": $fa-var-creative-commons-zero,\n \"hips\": $fa-var-hips,\n \"css\": $fa-var-css,\n \"behance\": $fa-var-behance,\n \"reddit\": $fa-var-reddit,\n \"discord\": $fa-var-discord,\n \"chrome\": $fa-var-chrome,\n \"app-store-ios\": $fa-var-app-store-ios,\n \"cc-discover\": $fa-var-cc-discover,\n \"wpbeginner\": $fa-var-wpbeginner,\n \"confluence\": $fa-var-confluence,\n \"shoelace\": $fa-var-shoelace,\n \"mdb\": $fa-var-mdb,\n \"dochub\": $fa-var-dochub,\n \"accessible-icon\": $fa-var-accessible-icon,\n \"ebay\": $fa-var-ebay,\n \"amazon\": $fa-var-amazon,\n \"unsplash\": $fa-var-unsplash,\n \"yarn\": $fa-var-yarn,\n \"square-steam\": $fa-var-square-steam,\n \"steam-square\": $fa-var-steam-square,\n \"500px\": $fa-var-500px,\n \"square-vimeo\": $fa-var-square-vimeo,\n \"vimeo-square\": $fa-var-vimeo-square,\n \"asymmetrik\": $fa-var-asymmetrik,\n \"font-awesome\": $fa-var-font-awesome,\n \"font-awesome-flag\": $fa-var-font-awesome-flag,\n \"font-awesome-logo-full\": $fa-var-font-awesome-logo-full,\n \"gratipay\": $fa-var-gratipay,\n \"apple\": $fa-var-apple,\n \"hive\": $fa-var-hive,\n \"gitkraken\": $fa-var-gitkraken,\n \"keybase\": $fa-var-keybase,\n \"apple-pay\": $fa-var-apple-pay,\n \"padlet\": $fa-var-padlet,\n \"amazon-pay\": $fa-var-amazon-pay,\n \"square-github\": $fa-var-square-github,\n \"github-square\": $fa-var-github-square,\n \"stumbleupon\": $fa-var-stumbleupon,\n \"fedex\": $fa-var-fedex,\n \"phoenix-framework\": $fa-var-phoenix-framework,\n \"shopify\": $fa-var-shopify,\n \"neos\": $fa-var-neos,\n \"square-threads\": $fa-var-square-threads,\n \"hackerrank\": $fa-var-hackerrank,\n \"researchgate\": $fa-var-researchgate,\n \"swift\": $fa-var-swift,\n \"angular\": $fa-var-angular,\n \"speakap\": $fa-var-speakap,\n \"angrycreative\": $fa-var-angrycreative,\n \"y-combinator\": $fa-var-y-combinator,\n \"empire\": $fa-var-empire,\n \"envira\": $fa-var-envira,\n \"google-scholar\": $fa-var-google-scholar,\n \"square-gitlab\": $fa-var-square-gitlab,\n \"gitlab-square\": $fa-var-gitlab-square,\n \"studiovinari\": $fa-var-studiovinari,\n \"pied-piper\": $fa-var-pied-piper,\n \"wordpress\": $fa-var-wordpress,\n \"product-hunt\": $fa-var-product-hunt,\n \"firefox\": $fa-var-firefox,\n \"linode\": $fa-var-linode,\n \"goodreads\": $fa-var-goodreads,\n \"square-odnoklassniki\": $fa-var-square-odnoklassniki,\n \"odnoklassniki-square\": $fa-var-odnoklassniki-square,\n \"jsfiddle\": $fa-var-jsfiddle,\n \"sith\": $fa-var-sith,\n \"themeisle\": $fa-var-themeisle,\n \"page4\": $fa-var-page4,\n \"hashnode\": $fa-var-hashnode,\n \"react\": $fa-var-react,\n \"cc-paypal\": $fa-var-cc-paypal,\n \"squarespace\": $fa-var-squarespace,\n \"cc-stripe\": $fa-var-cc-stripe,\n \"creative-commons-share\": $fa-var-creative-commons-share,\n \"bitcoin\": $fa-var-bitcoin,\n \"keycdn\": $fa-var-keycdn,\n \"opera\": $fa-var-opera,\n \"itch-io\": $fa-var-itch-io,\n \"umbraco\": $fa-var-umbraco,\n \"galactic-senate\": $fa-var-galactic-senate,\n \"ubuntu\": $fa-var-ubuntu,\n \"draft2digital\": $fa-var-draft2digital,\n \"stripe\": $fa-var-stripe,\n \"houzz\": $fa-var-houzz,\n \"gg\": $fa-var-gg,\n \"dhl\": $fa-var-dhl,\n \"square-pinterest\": $fa-var-square-pinterest,\n \"pinterest-square\": $fa-var-pinterest-square,\n \"xing\": $fa-var-xing,\n \"blackberry\": $fa-var-blackberry,\n \"creative-commons-pd\": $fa-var-creative-commons-pd,\n \"playstation\": $fa-var-playstation,\n \"quinscape\": $fa-var-quinscape,\n \"less\": $fa-var-less,\n \"blogger-b\": $fa-var-blogger-b,\n \"opencart\": $fa-var-opencart,\n \"vine\": $fa-var-vine,\n \"signal-messenger\": $fa-var-signal-messenger,\n \"paypal\": $fa-var-paypal,\n \"gitlab\": $fa-var-gitlab,\n \"typo3\": $fa-var-typo3,\n \"reddit-alien\": $fa-var-reddit-alien,\n \"yahoo\": $fa-var-yahoo,\n \"dailymotion\": $fa-var-dailymotion,\n \"affiliatetheme\": $fa-var-affiliatetheme,\n \"pied-piper-pp\": $fa-var-pied-piper-pp,\n \"bootstrap\": $fa-var-bootstrap,\n \"odnoklassniki\": $fa-var-odnoklassniki,\n \"nfc-symbol\": $fa-var-nfc-symbol,\n \"mintbit\": $fa-var-mintbit,\n \"ethereum\": $fa-var-ethereum,\n \"speaker-deck\": $fa-var-speaker-deck,\n \"creative-commons-nc-eu\": $fa-var-creative-commons-nc-eu,\n \"patreon\": $fa-var-patreon,\n \"avianex\": $fa-var-avianex,\n \"ello\": $fa-var-ello,\n \"gofore\": $fa-var-gofore,\n \"bimobject\": $fa-var-bimobject,\n \"brave-reverse\": $fa-var-brave-reverse,\n \"facebook-f\": $fa-var-facebook-f,\n \"square-google-plus\": $fa-var-square-google-plus,\n \"google-plus-square\": $fa-var-google-plus-square,\n \"web-awesome\": $fa-var-web-awesome,\n \"mandalorian\": $fa-var-mandalorian,\n \"first-order-alt\": $fa-var-first-order-alt,\n \"osi\": $fa-var-osi,\n \"google-wallet\": $fa-var-google-wallet,\n \"d-and-d-beyond\": $fa-var-d-and-d-beyond,\n \"periscope\": $fa-var-periscope,\n \"fulcrum\": $fa-var-fulcrum,\n \"cloudscale\": $fa-var-cloudscale,\n \"forumbee\": $fa-var-forumbee,\n \"mizuni\": $fa-var-mizuni,\n \"schlix\": $fa-var-schlix,\n \"square-xing\": $fa-var-square-xing,\n \"xing-square\": $fa-var-xing-square,\n \"bandcamp\": $fa-var-bandcamp,\n \"wpforms\": $fa-var-wpforms,\n \"cloudversify\": $fa-var-cloudversify,\n \"usps\": $fa-var-usps,\n \"megaport\": $fa-var-megaport,\n \"magento\": $fa-var-magento,\n \"spotify\": $fa-var-spotify,\n \"optin-monster\": $fa-var-optin-monster,\n \"fly\": $fa-var-fly,\n \"square-bluesky\": $fa-var-square-bluesky,\n \"aviato\": $fa-var-aviato,\n \"itunes\": $fa-var-itunes,\n \"cuttlefish\": $fa-var-cuttlefish,\n \"blogger\": $fa-var-blogger,\n \"flickr\": $fa-var-flickr,\n \"viber\": $fa-var-viber,\n \"soundcloud\": $fa-var-soundcloud,\n \"digg\": $fa-var-digg,\n \"tencent-weibo\": $fa-var-tencent-weibo,\n \"letterboxd\": $fa-var-letterboxd,\n \"symfony\": $fa-var-symfony,\n \"maxcdn\": $fa-var-maxcdn,\n \"etsy\": $fa-var-etsy,\n \"facebook-messenger\": $fa-var-facebook-messenger,\n \"audible\": $fa-var-audible,\n \"think-peaks\": $fa-var-think-peaks,\n \"bilibili\": $fa-var-bilibili,\n \"erlang\": $fa-var-erlang,\n \"x-twitter\": $fa-var-x-twitter,\n \"cotton-bureau\": $fa-var-cotton-bureau,\n \"dashcube\": $fa-var-dashcube,\n \"42-group\": $fa-var-42-group,\n \"innosoft\": $fa-var-innosoft,\n \"stack-exchange\": $fa-var-stack-exchange,\n \"elementor\": $fa-var-elementor,\n \"square-pied-piper\": $fa-var-square-pied-piper,\n \"pied-piper-square\": $fa-var-pied-piper-square,\n \"creative-commons-nd\": $fa-var-creative-commons-nd,\n \"palfed\": $fa-var-palfed,\n \"superpowers\": $fa-var-superpowers,\n \"resolving\": $fa-var-resolving,\n \"xbox\": $fa-var-xbox,\n \"square-web-awesome-stroke\": $fa-var-square-web-awesome-stroke,\n \"searchengin\": $fa-var-searchengin,\n \"tiktok\": $fa-var-tiktok,\n \"square-facebook\": $fa-var-square-facebook,\n \"facebook-square\": $fa-var-facebook-square,\n \"renren\": $fa-var-renren,\n \"linux\": $fa-var-linux,\n \"glide\": $fa-var-glide,\n \"linkedin\": $fa-var-linkedin,\n \"hubspot\": $fa-var-hubspot,\n \"deploydog\": $fa-var-deploydog,\n \"twitch\": $fa-var-twitch,\n \"flutter\": $fa-var-flutter,\n \"ravelry\": $fa-var-ravelry,\n \"mixer\": $fa-var-mixer,\n \"square-lastfm\": $fa-var-square-lastfm,\n \"lastfm-square\": $fa-var-lastfm-square,\n \"vimeo\": $fa-var-vimeo,\n \"mendeley\": $fa-var-mendeley,\n \"uniregistry\": $fa-var-uniregistry,\n \"figma\": $fa-var-figma,\n \"creative-commons-remix\": $fa-var-creative-commons-remix,\n \"cc-amazon-pay\": $fa-var-cc-amazon-pay,\n \"dropbox\": $fa-var-dropbox,\n \"instagram\": $fa-var-instagram,\n \"cmplid\": $fa-var-cmplid,\n \"upwork\": $fa-var-upwork,\n \"facebook\": $fa-var-facebook,\n \"gripfire\": $fa-var-gripfire,\n \"jedi-order\": $fa-var-jedi-order,\n \"uikit\": $fa-var-uikit,\n \"fort-awesome-alt\": $fa-var-fort-awesome-alt,\n \"phabricator\": $fa-var-phabricator,\n \"ussunnah\": $fa-var-ussunnah,\n \"earlybirds\": $fa-var-earlybirds,\n \"trade-federation\": $fa-var-trade-federation,\n \"autoprefixer\": $fa-var-autoprefixer,\n \"whatsapp\": $fa-var-whatsapp,\n \"square-upwork\": $fa-var-square-upwork,\n \"slideshare\": $fa-var-slideshare,\n \"google-play\": $fa-var-google-play,\n \"viadeo\": $fa-var-viadeo,\n \"line\": $fa-var-line,\n \"google-drive\": $fa-var-google-drive,\n \"servicestack\": $fa-var-servicestack,\n \"simplybuilt\": $fa-var-simplybuilt,\n \"bitbucket\": $fa-var-bitbucket,\n \"imdb\": $fa-var-imdb,\n \"deezer\": $fa-var-deezer,\n \"raspberry-pi\": $fa-var-raspberry-pi,\n \"jira\": $fa-var-jira,\n \"docker\": $fa-var-docker,\n \"screenpal\": $fa-var-screenpal,\n \"bluetooth\": $fa-var-bluetooth,\n \"gitter\": $fa-var-gitter,\n \"d-and-d\": $fa-var-d-and-d,\n \"microblog\": $fa-var-microblog,\n \"cc-diners-club\": $fa-var-cc-diners-club,\n \"gg-circle\": $fa-var-gg-circle,\n \"pied-piper-hat\": $fa-var-pied-piper-hat,\n \"kickstarter-k\": $fa-var-kickstarter-k,\n \"yandex\": $fa-var-yandex,\n \"readme\": $fa-var-readme,\n \"html5\": $fa-var-html5,\n \"sellsy\": $fa-var-sellsy,\n \"square-web-awesome\": $fa-var-square-web-awesome,\n \"sass\": $fa-var-sass,\n \"wirsindhandwerk\": $fa-var-wirsindhandwerk,\n \"wsh\": $fa-var-wsh,\n \"buromobelexperte\": $fa-var-buromobelexperte,\n \"salesforce\": $fa-var-salesforce,\n \"octopus-deploy\": $fa-var-octopus-deploy,\n \"medapps\": $fa-var-medapps,\n \"ns8\": $fa-var-ns8,\n \"pinterest-p\": $fa-var-pinterest-p,\n \"apper\": $fa-var-apper,\n \"fort-awesome\": $fa-var-fort-awesome,\n \"waze\": $fa-var-waze,\n \"bluesky\": $fa-var-bluesky,\n \"cc-jcb\": $fa-var-cc-jcb,\n \"snapchat\": $fa-var-snapchat,\n \"snapchat-ghost\": $fa-var-snapchat-ghost,\n \"fantasy-flight-games\": $fa-var-fantasy-flight-games,\n \"rust\": $fa-var-rust,\n \"wix\": $fa-var-wix,\n \"square-behance\": $fa-var-square-behance,\n \"behance-square\": $fa-var-behance-square,\n \"supple\": $fa-var-supple,\n \"webflow\": $fa-var-webflow,\n \"rebel\": $fa-var-rebel,\n \"css3\": $fa-var-css3,\n \"staylinked\": $fa-var-staylinked,\n \"kaggle\": $fa-var-kaggle,\n \"space-awesome\": $fa-var-space-awesome,\n \"deviantart\": $fa-var-deviantart,\n \"cpanel\": $fa-var-cpanel,\n \"goodreads-g\": $fa-var-goodreads-g,\n \"square-git\": $fa-var-square-git,\n \"git-square\": $fa-var-git-square,\n \"square-tumblr\": $fa-var-square-tumblr,\n \"tumblr-square\": $fa-var-tumblr-square,\n \"trello\": $fa-var-trello,\n \"creative-commons-nc-jp\": $fa-var-creative-commons-nc-jp,\n \"get-pocket\": $fa-var-get-pocket,\n \"perbyte\": $fa-var-perbyte,\n \"grunt\": $fa-var-grunt,\n \"weebly\": $fa-var-weebly,\n \"connectdevelop\": $fa-var-connectdevelop,\n \"leanpub\": $fa-var-leanpub,\n \"black-tie\": $fa-var-black-tie,\n \"themeco\": $fa-var-themeco,\n \"python\": $fa-var-python,\n \"android\": $fa-var-android,\n \"bots\": $fa-var-bots,\n \"free-code-camp\": $fa-var-free-code-camp,\n \"hornbill\": $fa-var-hornbill,\n \"js\": $fa-var-js,\n \"ideal\": $fa-var-ideal,\n \"git\": $fa-var-git,\n \"dev\": $fa-var-dev,\n \"sketch\": $fa-var-sketch,\n \"yandex-international\": $fa-var-yandex-international,\n \"cc-amex\": $fa-var-cc-amex,\n \"uber\": $fa-var-uber,\n \"github\": $fa-var-github,\n \"php\": $fa-var-php,\n \"alipay\": $fa-var-alipay,\n \"youtube\": $fa-var-youtube,\n \"skyatlas\": $fa-var-skyatlas,\n \"firefox-browser\": $fa-var-firefox-browser,\n \"replyd\": $fa-var-replyd,\n \"suse\": $fa-var-suse,\n \"jenkins\": $fa-var-jenkins,\n \"twitter\": $fa-var-twitter,\n \"rockrms\": $fa-var-rockrms,\n \"pinterest\": $fa-var-pinterest,\n \"buffer\": $fa-var-buffer,\n \"npm\": $fa-var-npm,\n \"yammer\": $fa-var-yammer,\n \"btc\": $fa-var-btc,\n \"dribbble\": $fa-var-dribbble,\n \"stumbleupon-circle\": $fa-var-stumbleupon-circle,\n \"internet-explorer\": $fa-var-internet-explorer,\n \"stubber\": $fa-var-stubber,\n \"telegram\": $fa-var-telegram,\n \"telegram-plane\": $fa-var-telegram-plane,\n \"old-republic\": $fa-var-old-republic,\n \"odysee\": $fa-var-odysee,\n \"square-whatsapp\": $fa-var-square-whatsapp,\n \"whatsapp-square\": $fa-var-whatsapp-square,\n \"node-js\": $fa-var-node-js,\n \"edge-legacy\": $fa-var-edge-legacy,\n \"slack\": $fa-var-slack,\n \"slack-hash\": $fa-var-slack-hash,\n \"medrt\": $fa-var-medrt,\n \"usb\": $fa-var-usb,\n \"tumblr\": $fa-var-tumblr,\n \"vaadin\": $fa-var-vaadin,\n \"quora\": $fa-var-quora,\n \"square-x-twitter\": $fa-var-square-x-twitter,\n \"reacteurope\": $fa-var-reacteurope,\n \"medium\": $fa-var-medium,\n \"medium-m\": $fa-var-medium-m,\n \"amilia\": $fa-var-amilia,\n \"mixcloud\": $fa-var-mixcloud,\n \"flipboard\": $fa-var-flipboard,\n \"viacoin\": $fa-var-viacoin,\n \"critical-role\": $fa-var-critical-role,\n \"sitrox\": $fa-var-sitrox,\n \"discourse\": $fa-var-discourse,\n \"joomla\": $fa-var-joomla,\n \"mastodon\": $fa-var-mastodon,\n \"airbnb\": $fa-var-airbnb,\n \"wolf-pack-battalion\": $fa-var-wolf-pack-battalion,\n \"buy-n-large\": $fa-var-buy-n-large,\n \"gulp\": $fa-var-gulp,\n \"creative-commons-sampling-plus\": $fa-var-creative-commons-sampling-plus,\n \"strava\": $fa-var-strava,\n \"ember\": $fa-var-ember,\n \"canadian-maple-leaf\": $fa-var-canadian-maple-leaf,\n \"teamspeak\": $fa-var-teamspeak,\n \"pushed\": $fa-var-pushed,\n \"wordpress-simple\": $fa-var-wordpress-simple,\n \"nutritionix\": $fa-var-nutritionix,\n \"wodu\": $fa-var-wodu,\n \"google-pay\": $fa-var-google-pay,\n \"intercom\": $fa-var-intercom,\n \"zhihu\": $fa-var-zhihu,\n \"korvue\": $fa-var-korvue,\n \"pix\": $fa-var-pix,\n \"steam-symbol\": $fa-var-steam-symbol,\n);\n", + "// mixins\n// --------------------------\n\n// base rendering for an icon\n@mixin fa-icon {\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n display: inline-block;\n font-style: normal;\n font-variant: normal;\n font-weight: normal;\n line-height: 1;\n}\n\n// sets relative font-sizing and alignment (in _sizing)\n@mixin fa-size ($font-size) {\n font-size: fa-divide($font-size, $fa-size-scale-base) * 1em; // converts step in sizing scale into an em-based value that's relative to the scale's base\n line-height: fa-divide(1, $font-size) * 1em; // sets the line-height of the icon back to that of it's parent\n vertical-align: (fa-divide(6, $font-size) - fa-divide(3, 8)) * 1em; // vertically centers the icon taking into account the surrounding text's descender\n}\n\n// only display content to screen readers\n// see: https://www.a11yproject.com/posts/2013-01-11-how-to-hide-content/\n// see: https://hugogiraudel.com/2016/10/13/css-hide-and-seek/\n@mixin fa-sr-only() {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border-width: 0;\n}\n\n// use in conjunction with .sr-only to only display content when it's focused\n@mixin fa-sr-only-focusable() {\n &:not(:focus) {\n @include fa-sr-only();\n }\n}\n\n// sets a specific icon family to use alongside style + icon mixins\n@mixin fa-family-classic() {\n @extend .fa-classic;\n}\n\n// convenience mixins for declaring pseudo-elements by CSS variable,\n// including all style-specific font properties\n@mixin fa-icon-solid($fa-var) {\n @extend .fa-solid;\n\n & { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var }\\\"\"); #{$fa-duotone-icon-property}: unquote(\"\\\"#{ $fa-var }#{ $fa-var }\\\"\"); }\n}\n@mixin fa-icon-regular($fa-var) {\n @extend .fa-regular;\n\n & { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var }\\\"\"); #{$fa-duotone-icon-property}: unquote(\"\\\"#{ $fa-var }#{ $fa-var }\\\"\"); }\n}\n@mixin fa-icon-brands($fa-var) {\n @extend .fa-brands;\n\n & { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var }\\\"\"); #{$fa-duotone-icon-property}: unquote(\"\\\"#{ $fa-var }#{ $fa-var }\\\"\"); }\n}\n", + "// base icon class definition\n// -------------------------\n\n.#{$fa-css-prefix} {\n font-family: var(--#{$fa-css-prefix}-style-family, '#{$fa-style-family}');\n font-weight: var(--#{$fa-css-prefix}-style, #{$fa-style});\n}\n\n.fas,\n.far,\n.fab,\n.#{$fa-css-prefix}-solid,\n.#{$fa-css-prefix}-regular,\n.#{$fa-css-prefix}-brands,\n.#{$fa-css-prefix} {\n -moz-osx-font-smoothing: grayscale;\n -webkit-font-smoothing: antialiased;\n display: var(--#{$fa-css-prefix}-display, #{$fa-display});\n font-style: normal;\n font-variant: normal;\n line-height: 1;\n text-rendering: auto;\n}\n\n.fas::before,\n.far::before,\n.fab::before,\n.#{$fa-css-prefix}-solid::before,\n.#{$fa-css-prefix}-regular::before,\n.#{$fa-css-prefix}-brands::before,\n.fa::before {\n content: var(#{$fa-icon-property});\n}\n\n.#{$fa-css-prefix}-classic,\n.fas,\n.#{$fa-css-prefix}-solid,\n.far,\n.#{$fa-css-prefix}-regular {\n font-family: 'Font Awesome 6 Free';\n}\n.#{$fa-css-prefix}-brands,\n.fab {\n font-family: 'Font Awesome 6 Brands';\n}\n\n%fa-icon {\n @include fa-icon;\n}\n", + "// sizing icons\n// -------------------------\n\n// literal magnification scale\n@for $i from 1 through 10 {\n .#{$fa-css-prefix}-#{$i}x {\n font-size: $i * 1em;\n }\n}\n\n// step-based scale (with alignment)\n@each $size, $value in $fa-sizes {\n .#{$fa-css-prefix}-#{$size} {\n @include fa-size($value);\n }\n}\n", + "// fixed-width icons\n// -------------------------\n\n.#{$fa-css-prefix}-fw {\n text-align: center;\n width: $fa-fw-width;\n}\n", + "// icons in a list\n// -------------------------\n\n.#{$fa-css-prefix}-ul {\n list-style-type: none;\n margin-left: var(--#{$fa-css-prefix}-li-margin, #{$fa-li-margin});\n padding-left: 0;\n\n > li { position: relative; }\n}\n\n.#{$fa-css-prefix}-li {\n left: calc(-1 * var(--#{$fa-css-prefix}-li-width, #{$fa-li-width}));\n position: absolute;\n text-align: center;\n width: var(--#{$fa-css-prefix}-li-width, #{$fa-li-width});\n line-height: inherit;\n}\n", + "// bordered + pulled icons\n// -------------------------\n\n.#{$fa-css-prefix}-border {\n border-color: var(--#{$fa-css-prefix}-border-color, #{$fa-border-color});\n border-radius: var(--#{$fa-css-prefix}-border-radius, #{$fa-border-radius});\n border-style: var(--#{$fa-css-prefix}-border-style, #{$fa-border-style});\n border-width: var(--#{$fa-css-prefix}-border-width, #{$fa-border-width});\n padding: var(--#{$fa-css-prefix}-border-padding, #{$fa-border-padding});\n}\n\n.#{$fa-css-prefix}-pull-left {\n float: left;\n margin-right: var(--#{$fa-css-prefix}-pull-margin, #{$fa-pull-margin}); \n}\n\n.#{$fa-css-prefix}-pull-right {\n float: right;\n margin-left: var(--#{$fa-css-prefix}-pull-margin, #{$fa-pull-margin}); \n}\n", + "// animating icons\n// --------------------------\n\n.#{$fa-css-prefix}-beat {\n animation-name: #{$fa-css-prefix}-beat;\n animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s);\n animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal);\n animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s);\n animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite);\n animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, ease-in-out);\n}\n\n.#{$fa-css-prefix}-bounce {\n animation-name: #{$fa-css-prefix}-bounce;\n animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s);\n animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal);\n animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s);\n animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite);\n animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, cubic-bezier(0.280, 0.840, 0.420, 1));\n}\n\n.#{$fa-css-prefix}-fade {\n animation-name: #{$fa-css-prefix}-fade;\n animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s);\n animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal);\n animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s);\n animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite);\n animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, cubic-bezier(.4,0,.6,1));\n}\n\n.#{$fa-css-prefix}-beat-fade {\n animation-name: #{$fa-css-prefix}-beat-fade;\n animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s);\n animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal);\n animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s);\n animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite);\n animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, cubic-bezier(.4,0,.6,1));\n}\n\n.#{$fa-css-prefix}-flip {\n animation-name: #{$fa-css-prefix}-flip;\n animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s);\n animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal);\n animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s);\n animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite);\n animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, ease-in-out);\n}\n\n.#{$fa-css-prefix}-shake {\n animation-name: #{$fa-css-prefix}-shake;\n animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s);\n animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal);\n animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s);\n animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite);\n animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, linear);\n}\n\n.#{$fa-css-prefix}-spin {\n animation-name: #{$fa-css-prefix}-spin;\n animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s);\n animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal);\n animation-duration: var(--#{$fa-css-prefix}-animation-duration, 2s);\n animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite);\n animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, linear);\n}\n\n.#{$fa-css-prefix}-spin-reverse {\n --#{$fa-css-prefix}-animation-direction: reverse;\n}\n\n.#{$fa-css-prefix}-pulse,\n.#{$fa-css-prefix}-spin-pulse {\n animation-name: #{$fa-css-prefix}-spin;\n animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal);\n animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s);\n animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite);\n animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, steps(8));\n}\n\n// if agent or operating system prefers reduced motion, disable animations\n// see: https://www.smashingmagazine.com/2020/09/design-reduced-motion-sensitivities/\n// see: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion\n@media (prefers-reduced-motion: reduce) {\n .#{$fa-css-prefix}-beat,\n .#{$fa-css-prefix}-bounce,\n .#{$fa-css-prefix}-fade,\n .#{$fa-css-prefix}-beat-fade,\n .#{$fa-css-prefix}-flip,\n .#{$fa-css-prefix}-pulse,\n .#{$fa-css-prefix}-shake,\n .#{$fa-css-prefix}-spin,\n .#{$fa-css-prefix}-spin-pulse {\n animation-delay: -1ms;\n animation-duration: 1ms;\n animation-iteration-count: 1;\n transition-delay: 0s;\n transition-duration: 0s;\n }\n}\n\n@keyframes #{$fa-css-prefix}-beat {\n 0%, 90% { transform: scale(1); }\n 45% { transform: scale(var(--#{$fa-css-prefix}-beat-scale, 1.25)); }\n}\n\n@keyframes #{$fa-css-prefix}-bounce {\n 0% { transform: scale(1,1) translateY(0); }\n 10% { transform: scale(var(--#{$fa-css-prefix}-bounce-start-scale-x, 1.1),var(--#{$fa-css-prefix}-bounce-start-scale-y, 0.9)) translateY(0); }\n 30% { transform: scale(var(--#{$fa-css-prefix}-bounce-jump-scale-x, 0.9),var(--#{$fa-css-prefix}-bounce-jump-scale-y, 1.1)) translateY(var(--#{$fa-css-prefix}-bounce-height, -0.5em)); }\n 50% { transform: scale(var(--#{$fa-css-prefix}-bounce-land-scale-x, 1.05),var(--#{$fa-css-prefix}-bounce-land-scale-y, 0.95)) translateY(0); }\n 57% { transform: scale(1,1) translateY(var(--#{$fa-css-prefix}-bounce-rebound, -0.125em)); }\n 64% { transform: scale(1,1) translateY(0); }\n 100% { transform: scale(1,1) translateY(0); }\n}\n\n@keyframes #{$fa-css-prefix}-fade {\n 50% { opacity: var(--#{$fa-css-prefix}-fade-opacity, 0.4); }\n}\n\n@keyframes #{$fa-css-prefix}-beat-fade {\n 0%, 100% {\n opacity: var(--#{$fa-css-prefix}-beat-fade-opacity, 0.4);\n transform: scale(1);\n }\n 50% {\n opacity: 1;\n transform: scale(var(--#{$fa-css-prefix}-beat-fade-scale, 1.125));\n }\n}\n\n@keyframes #{$fa-css-prefix}-flip {\n 50% {\n transform: rotate3d(var(--#{$fa-css-prefix}-flip-x, 0), var(--#{$fa-css-prefix}-flip-y, 1), var(--#{$fa-css-prefix}-flip-z, 0), var(--#{$fa-css-prefix}-flip-angle, -180deg));\n }\n}\n\n@keyframes #{$fa-css-prefix}-shake {\n 0% { transform: rotate(-15deg); }\n 4% { transform: rotate(15deg); }\n 8%, 24% { transform: rotate(-18deg); }\n 12%, 28% { transform: rotate(18deg); }\n 16% { transform: rotate(-22deg); }\n 20% { transform: rotate(22deg); }\n 32% { transform: rotate(-12deg); }\n 36% { transform: rotate(12deg); }\n 40%, 100% { transform: rotate(0deg); }\n}\n\n@keyframes #{$fa-css-prefix}-spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}\n", + "// rotating + flipping icons\n// -------------------------\n\n.#{$fa-css-prefix}-rotate-90 {\n transform: rotate(90deg);\n}\n\n.#{$fa-css-prefix}-rotate-180 {\n transform: rotate(180deg);\n}\n\n.#{$fa-css-prefix}-rotate-270 {\n transform: rotate(270deg);\n}\n\n.#{$fa-css-prefix}-flip-horizontal {\n transform: scale(-1, 1);\n}\n\n.#{$fa-css-prefix}-flip-vertical {\n transform: scale(1, -1);\n}\n\n.#{$fa-css-prefix}-flip-both,\n.#{$fa-css-prefix}-flip-horizontal.#{$fa-css-prefix}-flip-vertical {\n transform: scale(-1, -1);\n}\n\n.#{$fa-css-prefix}-rotate-by {\n transform: rotate(var(--#{$fa-css-prefix}-rotate-angle, 0));\n}\n", + "// stacking icons\n// -------------------------\n\n.#{$fa-css-prefix}-stack {\n display: inline-block;\n height: 2em;\n line-height: 2em;\n position: relative;\n vertical-align: $fa-stack-vertical-align;\n width: $fa-stack-width;\n}\n\n.#{$fa-css-prefix}-stack-1x,\n.#{$fa-css-prefix}-stack-2x {\n left: 0;\n position: absolute;\n text-align: center;\n width: 100%;\n z-index: var(--#{$fa-css-prefix}-stack-z-index, #{$fa-stack-z-index});\n}\n\n.#{$fa-css-prefix}-stack-1x {\n line-height: inherit;\n}\n\n.#{$fa-css-prefix}-stack-2x {\n font-size: 2em;\n}\n\n.#{$fa-css-prefix}-inverse {\n color: var(--#{$fa-css-prefix}-inverse, #{$fa-inverse});\n}\n", + "// specific icon class definition\n// -------------------------\n\n/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen\nreaders do not read off random characters that represent icons */\n\n@each $name, $icon in $fa-icons {\n .#{$fa-css-prefix}-#{$name} {\n #{$fa-icon-property}: unquote(\"\\\"#{ $icon }\\\"\");\n #{$fa-duotone-icon-property}: unquote(\"\\\"#{$icon}#{$icon}\\\"\");\n }\n}\n\n", + "// screen-reader utilities\n// -------------------------\n\n// only display content to screen readers\n.sr-only,\n.#{$fa-css-prefix}-sr-only {\n @include fa-sr-only;\n}\n\n// use in conjunction with .sr-only to only display content when it's focused\n.sr-only-focusable,\n.#{$fa-css-prefix}-sr-only-focusable {\n @include fa-sr-only-focusable;\n}\n", + "/*!\n * Font Awesome Free 6.7.1 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n * Copyright 2024 Fonticons, Inc.\n */\n@import 'functions';\n@import 'variables';\n\n:root, :host {\n --#{$fa-css-prefix}-style-family-classic: '#{ $fa-style-family }';\n --#{$fa-css-prefix}-font-regular: normal 400 1em/1 '#{ $fa-style-family }';\n}\n\n\n@font-face {\n font-family: 'Font Awesome 6 Free';\n font-style: normal;\n font-weight: 400;\n font-display: $fa-font-display;\n src: url('#{$fa-font-path}/fa-regular-400.woff2') format('woff2'),\n url('#{$fa-font-path}/fa-regular-400.ttf') format('truetype');\n}\n\n.far,\n.#{$fa-css-prefix}-regular {\n font-weight: 400;\n}\n", + "// functions\n// --------------------------\n\n// fa-content: convenience function used to set content property\n@function fa-content($fa-var) {\n @return unquote(\"\\\"#{ $fa-var }\\\"\");\n}\n\n// fa-divide: Originally obtained from the Bootstrap https://github.com/twbs/bootstrap\n//\n// Licensed under: The MIT License (MIT)\n//\n// Copyright (c) 2011-2021 Twitter, Inc.\n// Copyright (c) 2011-2021 The Bootstrap Authors\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n@function fa-divide($dividend, $divisor, $precision: 10) {\n $sign: if($dividend > 0 and $divisor > 0, 1, -1);\n $dividend: abs($dividend);\n $divisor: abs($divisor);\n $quotient: 0;\n $remainder: $dividend;\n @if $dividend == 0 {\n @return 0;\n }\n @if $divisor == 0 {\n @error \"Cannot divide by 0\";\n }\n @if $divisor == 1 {\n @return $dividend;\n }\n @while $remainder >= $divisor {\n $quotient: $quotient + 1;\n $remainder: $remainder - $divisor;\n }\n @if $remainder > 0 and $precision > 0 {\n $remainder: fa-divide($remainder * 10, $divisor, $precision - 1) * .1;\n }\n @return ($quotient + $remainder) * $sign;\n}\n", + "// variables\n// --------------------------\n\n$fa-css-prefix : fa !default;\n$fa-style : 900 !default;\n$fa-style-family : \"Font Awesome 6 Free\" !default;\n\n$fa-icon-property : --fa;\n$fa-duotone-icon-property : --fa--fa;\n\n$fa-display : inline-block !default;\n\n$fa-fw-width : fa-divide(20em, 16) !default;\n$fa-inverse : #fff !default;\n\n$fa-border-color : #eee !default;\n$fa-border-padding : .2em .25em .15em !default;\n$fa-border-radius : .1em !default;\n$fa-border-style : solid !default;\n$fa-border-width : .08em !default;\n\n$fa-size-scale-2xs : 10 !default;\n$fa-size-scale-xs : 12 !default;\n$fa-size-scale-sm : 14 !default;\n$fa-size-scale-base : 16 !default;\n$fa-size-scale-lg : 20 !default;\n$fa-size-scale-xl : 24 !default;\n$fa-size-scale-2xl : 32 !default;\n\n$fa-sizes: (\n \"2xs\" : $fa-size-scale-2xs,\n \"xs\" : $fa-size-scale-xs,\n \"sm\" : $fa-size-scale-sm,\n \"lg\" : $fa-size-scale-lg,\n \"xl\" : $fa-size-scale-xl,\n \"2xl\" : $fa-size-scale-2xl\n) !default;\n\n$fa-li-width : 2em !default;\n$fa-li-margin : $fa-li-width * fa-divide(5, 4) !default;\n\n$fa-pull-margin : .3em !default;\n\n$fa-primary-opacity : 1 !default;\n$fa-secondary-opacity : .4 !default;\n\n$fa-stack-vertical-align : middle !default;\n$fa-stack-width : ($fa-fw-width * 2) !default;\n$fa-stack-z-index : auto !default;\n\n$fa-font-display : block !default;\n$fa-font-path : \"../webfonts\" !default;\n\n$fa-var-0: \\30;\n$fa-var-1: \\31;\n$fa-var-2: \\32;\n$fa-var-3: \\33;\n$fa-var-4: \\34;\n$fa-var-5: \\35;\n$fa-var-6: \\36;\n$fa-var-7: \\37;\n$fa-var-8: \\38;\n$fa-var-9: \\39;\n$fa-var-fill-drip: \\f576;\n$fa-var-arrows-to-circle: \\e4bd;\n$fa-var-circle-chevron-right: \\f138;\n$fa-var-chevron-circle-right: \\f138;\n$fa-var-at: \\40;\n$fa-var-trash-can: \\f2ed;\n$fa-var-trash-alt: \\f2ed;\n$fa-var-text-height: \\f034;\n$fa-var-user-xmark: \\f235;\n$fa-var-user-times: \\f235;\n$fa-var-stethoscope: \\f0f1;\n$fa-var-message: \\f27a;\n$fa-var-comment-alt: \\f27a;\n$fa-var-info: \\f129;\n$fa-var-down-left-and-up-right-to-center: \\f422;\n$fa-var-compress-alt: \\f422;\n$fa-var-explosion: \\e4e9;\n$fa-var-file-lines: \\f15c;\n$fa-var-file-alt: \\f15c;\n$fa-var-file-text: \\f15c;\n$fa-var-wave-square: \\f83e;\n$fa-var-ring: \\f70b;\n$fa-var-building-un: \\e4d9;\n$fa-var-dice-three: \\f527;\n$fa-var-calendar-days: \\f073;\n$fa-var-calendar-alt: \\f073;\n$fa-var-anchor-circle-check: \\e4aa;\n$fa-var-building-circle-arrow-right: \\e4d1;\n$fa-var-volleyball: \\f45f;\n$fa-var-volleyball-ball: \\f45f;\n$fa-var-arrows-up-to-line: \\e4c2;\n$fa-var-sort-down: \\f0dd;\n$fa-var-sort-desc: \\f0dd;\n$fa-var-circle-minus: \\f056;\n$fa-var-minus-circle: \\f056;\n$fa-var-door-open: \\f52b;\n$fa-var-right-from-bracket: \\f2f5;\n$fa-var-sign-out-alt: \\f2f5;\n$fa-var-atom: \\f5d2;\n$fa-var-soap: \\e06e;\n$fa-var-icons: \\f86d;\n$fa-var-heart-music-camera-bolt: \\f86d;\n$fa-var-microphone-lines-slash: \\f539;\n$fa-var-microphone-alt-slash: \\f539;\n$fa-var-bridge-circle-check: \\e4c9;\n$fa-var-pump-medical: \\e06a;\n$fa-var-fingerprint: \\f577;\n$fa-var-hand-point-right: \\f0a4;\n$fa-var-magnifying-glass-location: \\f689;\n$fa-var-search-location: \\f689;\n$fa-var-forward-step: \\f051;\n$fa-var-step-forward: \\f051;\n$fa-var-face-smile-beam: \\f5b8;\n$fa-var-smile-beam: \\f5b8;\n$fa-var-flag-checkered: \\f11e;\n$fa-var-football: \\f44e;\n$fa-var-football-ball: \\f44e;\n$fa-var-school-circle-exclamation: \\e56c;\n$fa-var-crop: \\f125;\n$fa-var-angles-down: \\f103;\n$fa-var-angle-double-down: \\f103;\n$fa-var-users-rectangle: \\e594;\n$fa-var-people-roof: \\e537;\n$fa-var-people-line: \\e534;\n$fa-var-beer-mug-empty: \\f0fc;\n$fa-var-beer: \\f0fc;\n$fa-var-diagram-predecessor: \\e477;\n$fa-var-arrow-up-long: \\f176;\n$fa-var-long-arrow-up: \\f176;\n$fa-var-fire-flame-simple: \\f46a;\n$fa-var-burn: \\f46a;\n$fa-var-person: \\f183;\n$fa-var-male: \\f183;\n$fa-var-laptop: \\f109;\n$fa-var-file-csv: \\f6dd;\n$fa-var-menorah: \\f676;\n$fa-var-truck-plane: \\e58f;\n$fa-var-record-vinyl: \\f8d9;\n$fa-var-face-grin-stars: \\f587;\n$fa-var-grin-stars: \\f587;\n$fa-var-bong: \\f55c;\n$fa-var-spaghetti-monster-flying: \\f67b;\n$fa-var-pastafarianism: \\f67b;\n$fa-var-arrow-down-up-across-line: \\e4af;\n$fa-var-spoon: \\f2e5;\n$fa-var-utensil-spoon: \\f2e5;\n$fa-var-jar-wheat: \\e517;\n$fa-var-envelopes-bulk: \\f674;\n$fa-var-mail-bulk: \\f674;\n$fa-var-file-circle-exclamation: \\e4eb;\n$fa-var-circle-h: \\f47e;\n$fa-var-hospital-symbol: \\f47e;\n$fa-var-pager: \\f815;\n$fa-var-address-book: \\f2b9;\n$fa-var-contact-book: \\f2b9;\n$fa-var-strikethrough: \\f0cc;\n$fa-var-k: \\4b;\n$fa-var-landmark-flag: \\e51c;\n$fa-var-pencil: \\f303;\n$fa-var-pencil-alt: \\f303;\n$fa-var-backward: \\f04a;\n$fa-var-caret-right: \\f0da;\n$fa-var-comments: \\f086;\n$fa-var-paste: \\f0ea;\n$fa-var-file-clipboard: \\f0ea;\n$fa-var-code-pull-request: \\e13c;\n$fa-var-clipboard-list: \\f46d;\n$fa-var-truck-ramp-box: \\f4de;\n$fa-var-truck-loading: \\f4de;\n$fa-var-user-check: \\f4fc;\n$fa-var-vial-virus: \\e597;\n$fa-var-sheet-plastic: \\e571;\n$fa-var-blog: \\f781;\n$fa-var-user-ninja: \\f504;\n$fa-var-person-arrow-up-from-line: \\e539;\n$fa-var-scroll-torah: \\f6a0;\n$fa-var-torah: \\f6a0;\n$fa-var-broom-ball: \\f458;\n$fa-var-quidditch: \\f458;\n$fa-var-quidditch-broom-ball: \\f458;\n$fa-var-toggle-off: \\f204;\n$fa-var-box-archive: \\f187;\n$fa-var-archive: \\f187;\n$fa-var-person-drowning: \\e545;\n$fa-var-arrow-down-9-1: \\f886;\n$fa-var-sort-numeric-desc: \\f886;\n$fa-var-sort-numeric-down-alt: \\f886;\n$fa-var-face-grin-tongue-squint: \\f58a;\n$fa-var-grin-tongue-squint: \\f58a;\n$fa-var-spray-can: \\f5bd;\n$fa-var-truck-monster: \\f63b;\n$fa-var-w: \\57;\n$fa-var-earth-africa: \\f57c;\n$fa-var-globe-africa: \\f57c;\n$fa-var-rainbow: \\f75b;\n$fa-var-circle-notch: \\f1ce;\n$fa-var-tablet-screen-button: \\f3fa;\n$fa-var-tablet-alt: \\f3fa;\n$fa-var-paw: \\f1b0;\n$fa-var-cloud: \\f0c2;\n$fa-var-trowel-bricks: \\e58a;\n$fa-var-face-flushed: \\f579;\n$fa-var-flushed: \\f579;\n$fa-var-hospital-user: \\f80d;\n$fa-var-tent-arrow-left-right: \\e57f;\n$fa-var-gavel: \\f0e3;\n$fa-var-legal: \\f0e3;\n$fa-var-binoculars: \\f1e5;\n$fa-var-microphone-slash: \\f131;\n$fa-var-box-tissue: \\e05b;\n$fa-var-motorcycle: \\f21c;\n$fa-var-bell-concierge: \\f562;\n$fa-var-concierge-bell: \\f562;\n$fa-var-pen-ruler: \\f5ae;\n$fa-var-pencil-ruler: \\f5ae;\n$fa-var-people-arrows: \\e068;\n$fa-var-people-arrows-left-right: \\e068;\n$fa-var-mars-and-venus-burst: \\e523;\n$fa-var-square-caret-right: \\f152;\n$fa-var-caret-square-right: \\f152;\n$fa-var-scissors: \\f0c4;\n$fa-var-cut: \\f0c4;\n$fa-var-sun-plant-wilt: \\e57a;\n$fa-var-toilets-portable: \\e584;\n$fa-var-hockey-puck: \\f453;\n$fa-var-table: \\f0ce;\n$fa-var-magnifying-glass-arrow-right: \\e521;\n$fa-var-tachograph-digital: \\f566;\n$fa-var-digital-tachograph: \\f566;\n$fa-var-users-slash: \\e073;\n$fa-var-clover: \\e139;\n$fa-var-reply: \\f3e5;\n$fa-var-mail-reply: \\f3e5;\n$fa-var-star-and-crescent: \\f699;\n$fa-var-house-fire: \\e50c;\n$fa-var-square-minus: \\f146;\n$fa-var-minus-square: \\f146;\n$fa-var-helicopter: \\f533;\n$fa-var-compass: \\f14e;\n$fa-var-square-caret-down: \\f150;\n$fa-var-caret-square-down: \\f150;\n$fa-var-file-circle-question: \\e4ef;\n$fa-var-laptop-code: \\f5fc;\n$fa-var-swatchbook: \\f5c3;\n$fa-var-prescription-bottle: \\f485;\n$fa-var-bars: \\f0c9;\n$fa-var-navicon: \\f0c9;\n$fa-var-people-group: \\e533;\n$fa-var-hourglass-end: \\f253;\n$fa-var-hourglass-3: \\f253;\n$fa-var-heart-crack: \\f7a9;\n$fa-var-heart-broken: \\f7a9;\n$fa-var-square-up-right: \\f360;\n$fa-var-external-link-square-alt: \\f360;\n$fa-var-face-kiss-beam: \\f597;\n$fa-var-kiss-beam: \\f597;\n$fa-var-film: \\f008;\n$fa-var-ruler-horizontal: \\f547;\n$fa-var-people-robbery: \\e536;\n$fa-var-lightbulb: \\f0eb;\n$fa-var-caret-left: \\f0d9;\n$fa-var-circle-exclamation: \\f06a;\n$fa-var-exclamation-circle: \\f06a;\n$fa-var-school-circle-xmark: \\e56d;\n$fa-var-arrow-right-from-bracket: \\f08b;\n$fa-var-sign-out: \\f08b;\n$fa-var-circle-chevron-down: \\f13a;\n$fa-var-chevron-circle-down: \\f13a;\n$fa-var-unlock-keyhole: \\f13e;\n$fa-var-unlock-alt: \\f13e;\n$fa-var-cloud-showers-heavy: \\f740;\n$fa-var-headphones-simple: \\f58f;\n$fa-var-headphones-alt: \\f58f;\n$fa-var-sitemap: \\f0e8;\n$fa-var-circle-dollar-to-slot: \\f4b9;\n$fa-var-donate: \\f4b9;\n$fa-var-memory: \\f538;\n$fa-var-road-spikes: \\e568;\n$fa-var-fire-burner: \\e4f1;\n$fa-var-flag: \\f024;\n$fa-var-hanukiah: \\f6e6;\n$fa-var-feather: \\f52d;\n$fa-var-volume-low: \\f027;\n$fa-var-volume-down: \\f027;\n$fa-var-comment-slash: \\f4b3;\n$fa-var-cloud-sun-rain: \\f743;\n$fa-var-compress: \\f066;\n$fa-var-wheat-awn: \\e2cd;\n$fa-var-wheat-alt: \\e2cd;\n$fa-var-ankh: \\f644;\n$fa-var-hands-holding-child: \\e4fa;\n$fa-var-asterisk: \\2a;\n$fa-var-square-check: \\f14a;\n$fa-var-check-square: \\f14a;\n$fa-var-peseta-sign: \\e221;\n$fa-var-heading: \\f1dc;\n$fa-var-header: \\f1dc;\n$fa-var-ghost: \\f6e2;\n$fa-var-list: \\f03a;\n$fa-var-list-squares: \\f03a;\n$fa-var-square-phone-flip: \\f87b;\n$fa-var-phone-square-alt: \\f87b;\n$fa-var-cart-plus: \\f217;\n$fa-var-gamepad: \\f11b;\n$fa-var-circle-dot: \\f192;\n$fa-var-dot-circle: \\f192;\n$fa-var-face-dizzy: \\f567;\n$fa-var-dizzy: \\f567;\n$fa-var-egg: \\f7fb;\n$fa-var-house-medical-circle-xmark: \\e513;\n$fa-var-campground: \\f6bb;\n$fa-var-folder-plus: \\f65e;\n$fa-var-futbol: \\f1e3;\n$fa-var-futbol-ball: \\f1e3;\n$fa-var-soccer-ball: \\f1e3;\n$fa-var-paintbrush: \\f1fc;\n$fa-var-paint-brush: \\f1fc;\n$fa-var-lock: \\f023;\n$fa-var-gas-pump: \\f52f;\n$fa-var-hot-tub-person: \\f593;\n$fa-var-hot-tub: \\f593;\n$fa-var-map-location: \\f59f;\n$fa-var-map-marked: \\f59f;\n$fa-var-house-flood-water: \\e50e;\n$fa-var-tree: \\f1bb;\n$fa-var-bridge-lock: \\e4cc;\n$fa-var-sack-dollar: \\f81d;\n$fa-var-pen-to-square: \\f044;\n$fa-var-edit: \\f044;\n$fa-var-car-side: \\f5e4;\n$fa-var-share-nodes: \\f1e0;\n$fa-var-share-alt: \\f1e0;\n$fa-var-heart-circle-minus: \\e4ff;\n$fa-var-hourglass-half: \\f252;\n$fa-var-hourglass-2: \\f252;\n$fa-var-microscope: \\f610;\n$fa-var-sink: \\e06d;\n$fa-var-bag-shopping: \\f290;\n$fa-var-shopping-bag: \\f290;\n$fa-var-arrow-down-z-a: \\f881;\n$fa-var-sort-alpha-desc: \\f881;\n$fa-var-sort-alpha-down-alt: \\f881;\n$fa-var-mitten: \\f7b5;\n$fa-var-person-rays: \\e54d;\n$fa-var-users: \\f0c0;\n$fa-var-eye-slash: \\f070;\n$fa-var-flask-vial: \\e4f3;\n$fa-var-hand: \\f256;\n$fa-var-hand-paper: \\f256;\n$fa-var-om: \\f679;\n$fa-var-worm: \\e599;\n$fa-var-house-circle-xmark: \\e50b;\n$fa-var-plug: \\f1e6;\n$fa-var-chevron-up: \\f077;\n$fa-var-hand-spock: \\f259;\n$fa-var-stopwatch: \\f2f2;\n$fa-var-face-kiss: \\f596;\n$fa-var-kiss: \\f596;\n$fa-var-bridge-circle-xmark: \\e4cb;\n$fa-var-face-grin-tongue: \\f589;\n$fa-var-grin-tongue: \\f589;\n$fa-var-chess-bishop: \\f43a;\n$fa-var-face-grin-wink: \\f58c;\n$fa-var-grin-wink: \\f58c;\n$fa-var-ear-deaf: \\f2a4;\n$fa-var-deaf: \\f2a4;\n$fa-var-deafness: \\f2a4;\n$fa-var-hard-of-hearing: \\f2a4;\n$fa-var-road-circle-check: \\e564;\n$fa-var-dice-five: \\f523;\n$fa-var-square-rss: \\f143;\n$fa-var-rss-square: \\f143;\n$fa-var-land-mine-on: \\e51b;\n$fa-var-i-cursor: \\f246;\n$fa-var-stamp: \\f5bf;\n$fa-var-stairs: \\e289;\n$fa-var-i: \\49;\n$fa-var-hryvnia-sign: \\f6f2;\n$fa-var-hryvnia: \\f6f2;\n$fa-var-pills: \\f484;\n$fa-var-face-grin-wide: \\f581;\n$fa-var-grin-alt: \\f581;\n$fa-var-tooth: \\f5c9;\n$fa-var-v: \\56;\n$fa-var-bangladeshi-taka-sign: \\e2e6;\n$fa-var-bicycle: \\f206;\n$fa-var-staff-snake: \\e579;\n$fa-var-rod-asclepius: \\e579;\n$fa-var-rod-snake: \\e579;\n$fa-var-staff-aesculapius: \\e579;\n$fa-var-head-side-cough-slash: \\e062;\n$fa-var-truck-medical: \\f0f9;\n$fa-var-ambulance: \\f0f9;\n$fa-var-wheat-awn-circle-exclamation: \\e598;\n$fa-var-snowman: \\f7d0;\n$fa-var-mortar-pestle: \\f5a7;\n$fa-var-road-barrier: \\e562;\n$fa-var-school: \\f549;\n$fa-var-igloo: \\f7ae;\n$fa-var-joint: \\f595;\n$fa-var-angle-right: \\f105;\n$fa-var-horse: \\f6f0;\n$fa-var-q: \\51;\n$fa-var-g: \\47;\n$fa-var-notes-medical: \\f481;\n$fa-var-temperature-half: \\f2c9;\n$fa-var-temperature-2: \\f2c9;\n$fa-var-thermometer-2: \\f2c9;\n$fa-var-thermometer-half: \\f2c9;\n$fa-var-dong-sign: \\e169;\n$fa-var-capsules: \\f46b;\n$fa-var-poo-storm: \\f75a;\n$fa-var-poo-bolt: \\f75a;\n$fa-var-face-frown-open: \\f57a;\n$fa-var-frown-open: \\f57a;\n$fa-var-hand-point-up: \\f0a6;\n$fa-var-money-bill: \\f0d6;\n$fa-var-bookmark: \\f02e;\n$fa-var-align-justify: \\f039;\n$fa-var-umbrella-beach: \\f5ca;\n$fa-var-helmet-un: \\e503;\n$fa-var-bullseye: \\f140;\n$fa-var-bacon: \\f7e5;\n$fa-var-hand-point-down: \\f0a7;\n$fa-var-arrow-up-from-bracket: \\e09a;\n$fa-var-folder: \\f07b;\n$fa-var-folder-blank: \\f07b;\n$fa-var-file-waveform: \\f478;\n$fa-var-file-medical-alt: \\f478;\n$fa-var-radiation: \\f7b9;\n$fa-var-chart-simple: \\e473;\n$fa-var-mars-stroke: \\f229;\n$fa-var-vial: \\f492;\n$fa-var-gauge: \\f624;\n$fa-var-dashboard: \\f624;\n$fa-var-gauge-med: \\f624;\n$fa-var-tachometer-alt-average: \\f624;\n$fa-var-wand-magic-sparkles: \\e2ca;\n$fa-var-magic-wand-sparkles: \\e2ca;\n$fa-var-e: \\45;\n$fa-var-pen-clip: \\f305;\n$fa-var-pen-alt: \\f305;\n$fa-var-bridge-circle-exclamation: \\e4ca;\n$fa-var-user: \\f007;\n$fa-var-school-circle-check: \\e56b;\n$fa-var-dumpster: \\f793;\n$fa-var-van-shuttle: \\f5b6;\n$fa-var-shuttle-van: \\f5b6;\n$fa-var-building-user: \\e4da;\n$fa-var-square-caret-left: \\f191;\n$fa-var-caret-square-left: \\f191;\n$fa-var-highlighter: \\f591;\n$fa-var-key: \\f084;\n$fa-var-bullhorn: \\f0a1;\n$fa-var-globe: \\f0ac;\n$fa-var-synagogue: \\f69b;\n$fa-var-person-half-dress: \\e548;\n$fa-var-road-bridge: \\e563;\n$fa-var-location-arrow: \\f124;\n$fa-var-c: \\43;\n$fa-var-tablet-button: \\f10a;\n$fa-var-building-lock: \\e4d6;\n$fa-var-pizza-slice: \\f818;\n$fa-var-money-bill-wave: \\f53a;\n$fa-var-chart-area: \\f1fe;\n$fa-var-area-chart: \\f1fe;\n$fa-var-house-flag: \\e50d;\n$fa-var-person-circle-minus: \\e540;\n$fa-var-ban: \\f05e;\n$fa-var-cancel: \\f05e;\n$fa-var-camera-rotate: \\e0d8;\n$fa-var-spray-can-sparkles: \\f5d0;\n$fa-var-air-freshener: \\f5d0;\n$fa-var-star: \\f005;\n$fa-var-repeat: \\f363;\n$fa-var-cross: \\f654;\n$fa-var-box: \\f466;\n$fa-var-venus-mars: \\f228;\n$fa-var-arrow-pointer: \\f245;\n$fa-var-mouse-pointer: \\f245;\n$fa-var-maximize: \\f31e;\n$fa-var-expand-arrows-alt: \\f31e;\n$fa-var-charging-station: \\f5e7;\n$fa-var-shapes: \\f61f;\n$fa-var-triangle-circle-square: \\f61f;\n$fa-var-shuffle: \\f074;\n$fa-var-random: \\f074;\n$fa-var-person-running: \\f70c;\n$fa-var-running: \\f70c;\n$fa-var-mobile-retro: \\e527;\n$fa-var-grip-lines-vertical: \\f7a5;\n$fa-var-spider: \\f717;\n$fa-var-hands-bound: \\e4f9;\n$fa-var-file-invoice-dollar: \\f571;\n$fa-var-plane-circle-exclamation: \\e556;\n$fa-var-x-ray: \\f497;\n$fa-var-spell-check: \\f891;\n$fa-var-slash: \\f715;\n$fa-var-computer-mouse: \\f8cc;\n$fa-var-mouse: \\f8cc;\n$fa-var-arrow-right-to-bracket: \\f090;\n$fa-var-sign-in: \\f090;\n$fa-var-shop-slash: \\e070;\n$fa-var-store-alt-slash: \\e070;\n$fa-var-server: \\f233;\n$fa-var-virus-covid-slash: \\e4a9;\n$fa-var-shop-lock: \\e4a5;\n$fa-var-hourglass-start: \\f251;\n$fa-var-hourglass-1: \\f251;\n$fa-var-blender-phone: \\f6b6;\n$fa-var-building-wheat: \\e4db;\n$fa-var-person-breastfeeding: \\e53a;\n$fa-var-right-to-bracket: \\f2f6;\n$fa-var-sign-in-alt: \\f2f6;\n$fa-var-venus: \\f221;\n$fa-var-passport: \\f5ab;\n$fa-var-thumbtack-slash: \\e68f;\n$fa-var-thumb-tack-slash: \\e68f;\n$fa-var-heart-pulse: \\f21e;\n$fa-var-heartbeat: \\f21e;\n$fa-var-people-carry-box: \\f4ce;\n$fa-var-people-carry: \\f4ce;\n$fa-var-temperature-high: \\f769;\n$fa-var-microchip: \\f2db;\n$fa-var-crown: \\f521;\n$fa-var-weight-hanging: \\f5cd;\n$fa-var-xmarks-lines: \\e59a;\n$fa-var-file-prescription: \\f572;\n$fa-var-weight-scale: \\f496;\n$fa-var-weight: \\f496;\n$fa-var-user-group: \\f500;\n$fa-var-user-friends: \\f500;\n$fa-var-arrow-up-a-z: \\f15e;\n$fa-var-sort-alpha-up: \\f15e;\n$fa-var-chess-knight: \\f441;\n$fa-var-face-laugh-squint: \\f59b;\n$fa-var-laugh-squint: \\f59b;\n$fa-var-wheelchair: \\f193;\n$fa-var-circle-arrow-up: \\f0aa;\n$fa-var-arrow-circle-up: \\f0aa;\n$fa-var-toggle-on: \\f205;\n$fa-var-person-walking: \\f554;\n$fa-var-walking: \\f554;\n$fa-var-l: \\4c;\n$fa-var-fire: \\f06d;\n$fa-var-bed-pulse: \\f487;\n$fa-var-procedures: \\f487;\n$fa-var-shuttle-space: \\f197;\n$fa-var-space-shuttle: \\f197;\n$fa-var-face-laugh: \\f599;\n$fa-var-laugh: \\f599;\n$fa-var-folder-open: \\f07c;\n$fa-var-heart-circle-plus: \\e500;\n$fa-var-code-fork: \\e13b;\n$fa-var-city: \\f64f;\n$fa-var-microphone-lines: \\f3c9;\n$fa-var-microphone-alt: \\f3c9;\n$fa-var-pepper-hot: \\f816;\n$fa-var-unlock: \\f09c;\n$fa-var-colon-sign: \\e140;\n$fa-var-headset: \\f590;\n$fa-var-store-slash: \\e071;\n$fa-var-road-circle-xmark: \\e566;\n$fa-var-user-minus: \\f503;\n$fa-var-mars-stroke-up: \\f22a;\n$fa-var-mars-stroke-v: \\f22a;\n$fa-var-champagne-glasses: \\f79f;\n$fa-var-glass-cheers: \\f79f;\n$fa-var-clipboard: \\f328;\n$fa-var-house-circle-exclamation: \\e50a;\n$fa-var-file-arrow-up: \\f574;\n$fa-var-file-upload: \\f574;\n$fa-var-wifi: \\f1eb;\n$fa-var-wifi-3: \\f1eb;\n$fa-var-wifi-strong: \\f1eb;\n$fa-var-bath: \\f2cd;\n$fa-var-bathtub: \\f2cd;\n$fa-var-underline: \\f0cd;\n$fa-var-user-pen: \\f4ff;\n$fa-var-user-edit: \\f4ff;\n$fa-var-signature: \\f5b7;\n$fa-var-stroopwafel: \\f551;\n$fa-var-bold: \\f032;\n$fa-var-anchor-lock: \\e4ad;\n$fa-var-building-ngo: \\e4d7;\n$fa-var-manat-sign: \\e1d5;\n$fa-var-not-equal: \\f53e;\n$fa-var-border-top-left: \\f853;\n$fa-var-border-style: \\f853;\n$fa-var-map-location-dot: \\f5a0;\n$fa-var-map-marked-alt: \\f5a0;\n$fa-var-jedi: \\f669;\n$fa-var-square-poll-vertical: \\f681;\n$fa-var-poll: \\f681;\n$fa-var-mug-hot: \\f7b6;\n$fa-var-car-battery: \\f5df;\n$fa-var-battery-car: \\f5df;\n$fa-var-gift: \\f06b;\n$fa-var-dice-two: \\f528;\n$fa-var-chess-queen: \\f445;\n$fa-var-glasses: \\f530;\n$fa-var-chess-board: \\f43c;\n$fa-var-building-circle-check: \\e4d2;\n$fa-var-person-chalkboard: \\e53d;\n$fa-var-mars-stroke-right: \\f22b;\n$fa-var-mars-stroke-h: \\f22b;\n$fa-var-hand-back-fist: \\f255;\n$fa-var-hand-rock: \\f255;\n$fa-var-square-caret-up: \\f151;\n$fa-var-caret-square-up: \\f151;\n$fa-var-cloud-showers-water: \\e4e4;\n$fa-var-chart-bar: \\f080;\n$fa-var-bar-chart: \\f080;\n$fa-var-hands-bubbles: \\e05e;\n$fa-var-hands-wash: \\e05e;\n$fa-var-less-than-equal: \\f537;\n$fa-var-train: \\f238;\n$fa-var-eye-low-vision: \\f2a8;\n$fa-var-low-vision: \\f2a8;\n$fa-var-crow: \\f520;\n$fa-var-sailboat: \\e445;\n$fa-var-window-restore: \\f2d2;\n$fa-var-square-plus: \\f0fe;\n$fa-var-plus-square: \\f0fe;\n$fa-var-torii-gate: \\f6a1;\n$fa-var-frog: \\f52e;\n$fa-var-bucket: \\e4cf;\n$fa-var-image: \\f03e;\n$fa-var-microphone: \\f130;\n$fa-var-cow: \\f6c8;\n$fa-var-caret-up: \\f0d8;\n$fa-var-screwdriver: \\f54a;\n$fa-var-folder-closed: \\e185;\n$fa-var-house-tsunami: \\e515;\n$fa-var-square-nfi: \\e576;\n$fa-var-arrow-up-from-ground-water: \\e4b5;\n$fa-var-martini-glass: \\f57b;\n$fa-var-glass-martini-alt: \\f57b;\n$fa-var-square-binary: \\e69b;\n$fa-var-rotate-left: \\f2ea;\n$fa-var-rotate-back: \\f2ea;\n$fa-var-rotate-backward: \\f2ea;\n$fa-var-undo-alt: \\f2ea;\n$fa-var-table-columns: \\f0db;\n$fa-var-columns: \\f0db;\n$fa-var-lemon: \\f094;\n$fa-var-head-side-mask: \\e063;\n$fa-var-handshake: \\f2b5;\n$fa-var-gem: \\f3a5;\n$fa-var-dolly: \\f472;\n$fa-var-dolly-box: \\f472;\n$fa-var-smoking: \\f48d;\n$fa-var-minimize: \\f78c;\n$fa-var-compress-arrows-alt: \\f78c;\n$fa-var-monument: \\f5a6;\n$fa-var-snowplow: \\f7d2;\n$fa-var-angles-right: \\f101;\n$fa-var-angle-double-right: \\f101;\n$fa-var-cannabis: \\f55f;\n$fa-var-circle-play: \\f144;\n$fa-var-play-circle: \\f144;\n$fa-var-tablets: \\f490;\n$fa-var-ethernet: \\f796;\n$fa-var-euro-sign: \\f153;\n$fa-var-eur: \\f153;\n$fa-var-euro: \\f153;\n$fa-var-chair: \\f6c0;\n$fa-var-circle-check: \\f058;\n$fa-var-check-circle: \\f058;\n$fa-var-circle-stop: \\f28d;\n$fa-var-stop-circle: \\f28d;\n$fa-var-compass-drafting: \\f568;\n$fa-var-drafting-compass: \\f568;\n$fa-var-plate-wheat: \\e55a;\n$fa-var-icicles: \\f7ad;\n$fa-var-person-shelter: \\e54f;\n$fa-var-neuter: \\f22c;\n$fa-var-id-badge: \\f2c1;\n$fa-var-marker: \\f5a1;\n$fa-var-face-laugh-beam: \\f59a;\n$fa-var-laugh-beam: \\f59a;\n$fa-var-helicopter-symbol: \\e502;\n$fa-var-universal-access: \\f29a;\n$fa-var-circle-chevron-up: \\f139;\n$fa-var-chevron-circle-up: \\f139;\n$fa-var-lari-sign: \\e1c8;\n$fa-var-volcano: \\f770;\n$fa-var-person-walking-dashed-line-arrow-right: \\e553;\n$fa-var-sterling-sign: \\f154;\n$fa-var-gbp: \\f154;\n$fa-var-pound-sign: \\f154;\n$fa-var-viruses: \\e076;\n$fa-var-square-person-confined: \\e577;\n$fa-var-user-tie: \\f508;\n$fa-var-arrow-down-long: \\f175;\n$fa-var-long-arrow-down: \\f175;\n$fa-var-tent-arrow-down-to-line: \\e57e;\n$fa-var-certificate: \\f0a3;\n$fa-var-reply-all: \\f122;\n$fa-var-mail-reply-all: \\f122;\n$fa-var-suitcase: \\f0f2;\n$fa-var-person-skating: \\f7c5;\n$fa-var-skating: \\f7c5;\n$fa-var-filter-circle-dollar: \\f662;\n$fa-var-funnel-dollar: \\f662;\n$fa-var-camera-retro: \\f083;\n$fa-var-circle-arrow-down: \\f0ab;\n$fa-var-arrow-circle-down: \\f0ab;\n$fa-var-file-import: \\f56f;\n$fa-var-arrow-right-to-file: \\f56f;\n$fa-var-square-arrow-up-right: \\f14c;\n$fa-var-external-link-square: \\f14c;\n$fa-var-box-open: \\f49e;\n$fa-var-scroll: \\f70e;\n$fa-var-spa: \\f5bb;\n$fa-var-location-pin-lock: \\e51f;\n$fa-var-pause: \\f04c;\n$fa-var-hill-avalanche: \\e507;\n$fa-var-temperature-empty: \\f2cb;\n$fa-var-temperature-0: \\f2cb;\n$fa-var-thermometer-0: \\f2cb;\n$fa-var-thermometer-empty: \\f2cb;\n$fa-var-bomb: \\f1e2;\n$fa-var-registered: \\f25d;\n$fa-var-address-card: \\f2bb;\n$fa-var-contact-card: \\f2bb;\n$fa-var-vcard: \\f2bb;\n$fa-var-scale-unbalanced-flip: \\f516;\n$fa-var-balance-scale-right: \\f516;\n$fa-var-subscript: \\f12c;\n$fa-var-diamond-turn-right: \\f5eb;\n$fa-var-directions: \\f5eb;\n$fa-var-burst: \\e4dc;\n$fa-var-house-laptop: \\e066;\n$fa-var-laptop-house: \\e066;\n$fa-var-face-tired: \\f5c8;\n$fa-var-tired: \\f5c8;\n$fa-var-money-bills: \\e1f3;\n$fa-var-smog: \\f75f;\n$fa-var-crutch: \\f7f7;\n$fa-var-cloud-arrow-up: \\f0ee;\n$fa-var-cloud-upload: \\f0ee;\n$fa-var-cloud-upload-alt: \\f0ee;\n$fa-var-palette: \\f53f;\n$fa-var-arrows-turn-right: \\e4c0;\n$fa-var-vest: \\e085;\n$fa-var-ferry: \\e4ea;\n$fa-var-arrows-down-to-people: \\e4b9;\n$fa-var-seedling: \\f4d8;\n$fa-var-sprout: \\f4d8;\n$fa-var-left-right: \\f337;\n$fa-var-arrows-alt-h: \\f337;\n$fa-var-boxes-packing: \\e4c7;\n$fa-var-circle-arrow-left: \\f0a8;\n$fa-var-arrow-circle-left: \\f0a8;\n$fa-var-group-arrows-rotate: \\e4f6;\n$fa-var-bowl-food: \\e4c6;\n$fa-var-candy-cane: \\f786;\n$fa-var-arrow-down-wide-short: \\f160;\n$fa-var-sort-amount-asc: \\f160;\n$fa-var-sort-amount-down: \\f160;\n$fa-var-cloud-bolt: \\f76c;\n$fa-var-thunderstorm: \\f76c;\n$fa-var-text-slash: \\f87d;\n$fa-var-remove-format: \\f87d;\n$fa-var-face-smile-wink: \\f4da;\n$fa-var-smile-wink: \\f4da;\n$fa-var-file-word: \\f1c2;\n$fa-var-file-powerpoint: \\f1c4;\n$fa-var-arrows-left-right: \\f07e;\n$fa-var-arrows-h: \\f07e;\n$fa-var-house-lock: \\e510;\n$fa-var-cloud-arrow-down: \\f0ed;\n$fa-var-cloud-download: \\f0ed;\n$fa-var-cloud-download-alt: \\f0ed;\n$fa-var-children: \\e4e1;\n$fa-var-chalkboard: \\f51b;\n$fa-var-blackboard: \\f51b;\n$fa-var-user-large-slash: \\f4fa;\n$fa-var-user-alt-slash: \\f4fa;\n$fa-var-envelope-open: \\f2b6;\n$fa-var-handshake-simple-slash: \\e05f;\n$fa-var-handshake-alt-slash: \\e05f;\n$fa-var-mattress-pillow: \\e525;\n$fa-var-guarani-sign: \\e19a;\n$fa-var-arrows-rotate: \\f021;\n$fa-var-refresh: \\f021;\n$fa-var-sync: \\f021;\n$fa-var-fire-extinguisher: \\f134;\n$fa-var-cruzeiro-sign: \\e152;\n$fa-var-greater-than-equal: \\f532;\n$fa-var-shield-halved: \\f3ed;\n$fa-var-shield-alt: \\f3ed;\n$fa-var-book-atlas: \\f558;\n$fa-var-atlas: \\f558;\n$fa-var-virus: \\e074;\n$fa-var-envelope-circle-check: \\e4e8;\n$fa-var-layer-group: \\f5fd;\n$fa-var-arrows-to-dot: \\e4be;\n$fa-var-archway: \\f557;\n$fa-var-heart-circle-check: \\e4fd;\n$fa-var-house-chimney-crack: \\f6f1;\n$fa-var-house-damage: \\f6f1;\n$fa-var-file-zipper: \\f1c6;\n$fa-var-file-archive: \\f1c6;\n$fa-var-square: \\f0c8;\n$fa-var-martini-glass-empty: \\f000;\n$fa-var-glass-martini: \\f000;\n$fa-var-couch: \\f4b8;\n$fa-var-cedi-sign: \\e0df;\n$fa-var-italic: \\f033;\n$fa-var-table-cells-column-lock: \\e678;\n$fa-var-church: \\f51d;\n$fa-var-comments-dollar: \\f653;\n$fa-var-democrat: \\f747;\n$fa-var-z: \\5a;\n$fa-var-person-skiing: \\f7c9;\n$fa-var-skiing: \\f7c9;\n$fa-var-road-lock: \\e567;\n$fa-var-a: \\41;\n$fa-var-temperature-arrow-down: \\e03f;\n$fa-var-temperature-down: \\e03f;\n$fa-var-feather-pointed: \\f56b;\n$fa-var-feather-alt: \\f56b;\n$fa-var-p: \\50;\n$fa-var-snowflake: \\f2dc;\n$fa-var-newspaper: \\f1ea;\n$fa-var-rectangle-ad: \\f641;\n$fa-var-ad: \\f641;\n$fa-var-circle-arrow-right: \\f0a9;\n$fa-var-arrow-circle-right: \\f0a9;\n$fa-var-filter-circle-xmark: \\e17b;\n$fa-var-locust: \\e520;\n$fa-var-sort: \\f0dc;\n$fa-var-unsorted: \\f0dc;\n$fa-var-list-ol: \\f0cb;\n$fa-var-list-1-2: \\f0cb;\n$fa-var-list-numeric: \\f0cb;\n$fa-var-person-dress-burst: \\e544;\n$fa-var-money-check-dollar: \\f53d;\n$fa-var-money-check-alt: \\f53d;\n$fa-var-vector-square: \\f5cb;\n$fa-var-bread-slice: \\f7ec;\n$fa-var-language: \\f1ab;\n$fa-var-face-kiss-wink-heart: \\f598;\n$fa-var-kiss-wink-heart: \\f598;\n$fa-var-filter: \\f0b0;\n$fa-var-question: \\3f;\n$fa-var-file-signature: \\f573;\n$fa-var-up-down-left-right: \\f0b2;\n$fa-var-arrows-alt: \\f0b2;\n$fa-var-house-chimney-user: \\e065;\n$fa-var-hand-holding-heart: \\f4be;\n$fa-var-puzzle-piece: \\f12e;\n$fa-var-money-check: \\f53c;\n$fa-var-star-half-stroke: \\f5c0;\n$fa-var-star-half-alt: \\f5c0;\n$fa-var-code: \\f121;\n$fa-var-whiskey-glass: \\f7a0;\n$fa-var-glass-whiskey: \\f7a0;\n$fa-var-building-circle-exclamation: \\e4d3;\n$fa-var-magnifying-glass-chart: \\e522;\n$fa-var-arrow-up-right-from-square: \\f08e;\n$fa-var-external-link: \\f08e;\n$fa-var-cubes-stacked: \\e4e6;\n$fa-var-won-sign: \\f159;\n$fa-var-krw: \\f159;\n$fa-var-won: \\f159;\n$fa-var-virus-covid: \\e4a8;\n$fa-var-austral-sign: \\e0a9;\n$fa-var-f: \\46;\n$fa-var-leaf: \\f06c;\n$fa-var-road: \\f018;\n$fa-var-taxi: \\f1ba;\n$fa-var-cab: \\f1ba;\n$fa-var-person-circle-plus: \\e541;\n$fa-var-chart-pie: \\f200;\n$fa-var-pie-chart: \\f200;\n$fa-var-bolt-lightning: \\e0b7;\n$fa-var-sack-xmark: \\e56a;\n$fa-var-file-excel: \\f1c3;\n$fa-var-file-contract: \\f56c;\n$fa-var-fish-fins: \\e4f2;\n$fa-var-building-flag: \\e4d5;\n$fa-var-face-grin-beam: \\f582;\n$fa-var-grin-beam: \\f582;\n$fa-var-object-ungroup: \\f248;\n$fa-var-poop: \\f619;\n$fa-var-location-pin: \\f041;\n$fa-var-map-marker: \\f041;\n$fa-var-kaaba: \\f66b;\n$fa-var-toilet-paper: \\f71e;\n$fa-var-helmet-safety: \\f807;\n$fa-var-hard-hat: \\f807;\n$fa-var-hat-hard: \\f807;\n$fa-var-eject: \\f052;\n$fa-var-circle-right: \\f35a;\n$fa-var-arrow-alt-circle-right: \\f35a;\n$fa-var-plane-circle-check: \\e555;\n$fa-var-face-rolling-eyes: \\f5a5;\n$fa-var-meh-rolling-eyes: \\f5a5;\n$fa-var-object-group: \\f247;\n$fa-var-chart-line: \\f201;\n$fa-var-line-chart: \\f201;\n$fa-var-mask-ventilator: \\e524;\n$fa-var-arrow-right: \\f061;\n$fa-var-signs-post: \\f277;\n$fa-var-map-signs: \\f277;\n$fa-var-cash-register: \\f788;\n$fa-var-person-circle-question: \\e542;\n$fa-var-h: \\48;\n$fa-var-tarp: \\e57b;\n$fa-var-screwdriver-wrench: \\f7d9;\n$fa-var-tools: \\f7d9;\n$fa-var-arrows-to-eye: \\e4bf;\n$fa-var-plug-circle-bolt: \\e55b;\n$fa-var-heart: \\f004;\n$fa-var-mars-and-venus: \\f224;\n$fa-var-house-user: \\e1b0;\n$fa-var-home-user: \\e1b0;\n$fa-var-dumpster-fire: \\f794;\n$fa-var-house-crack: \\e3b1;\n$fa-var-martini-glass-citrus: \\f561;\n$fa-var-cocktail: \\f561;\n$fa-var-face-surprise: \\f5c2;\n$fa-var-surprise: \\f5c2;\n$fa-var-bottle-water: \\e4c5;\n$fa-var-circle-pause: \\f28b;\n$fa-var-pause-circle: \\f28b;\n$fa-var-toilet-paper-slash: \\e072;\n$fa-var-apple-whole: \\f5d1;\n$fa-var-apple-alt: \\f5d1;\n$fa-var-kitchen-set: \\e51a;\n$fa-var-r: \\52;\n$fa-var-temperature-quarter: \\f2ca;\n$fa-var-temperature-1: \\f2ca;\n$fa-var-thermometer-1: \\f2ca;\n$fa-var-thermometer-quarter: \\f2ca;\n$fa-var-cube: \\f1b2;\n$fa-var-bitcoin-sign: \\e0b4;\n$fa-var-shield-dog: \\e573;\n$fa-var-solar-panel: \\f5ba;\n$fa-var-lock-open: \\f3c1;\n$fa-var-elevator: \\e16d;\n$fa-var-money-bill-transfer: \\e528;\n$fa-var-money-bill-trend-up: \\e529;\n$fa-var-house-flood-water-circle-arrow-right: \\e50f;\n$fa-var-square-poll-horizontal: \\f682;\n$fa-var-poll-h: \\f682;\n$fa-var-circle: \\f111;\n$fa-var-backward-fast: \\f049;\n$fa-var-fast-backward: \\f049;\n$fa-var-recycle: \\f1b8;\n$fa-var-user-astronaut: \\f4fb;\n$fa-var-plane-slash: \\e069;\n$fa-var-trademark: \\f25c;\n$fa-var-basketball: \\f434;\n$fa-var-basketball-ball: \\f434;\n$fa-var-satellite-dish: \\f7c0;\n$fa-var-circle-up: \\f35b;\n$fa-var-arrow-alt-circle-up: \\f35b;\n$fa-var-mobile-screen-button: \\f3cd;\n$fa-var-mobile-alt: \\f3cd;\n$fa-var-volume-high: \\f028;\n$fa-var-volume-up: \\f028;\n$fa-var-users-rays: \\e593;\n$fa-var-wallet: \\f555;\n$fa-var-clipboard-check: \\f46c;\n$fa-var-file-audio: \\f1c7;\n$fa-var-burger: \\f805;\n$fa-var-hamburger: \\f805;\n$fa-var-wrench: \\f0ad;\n$fa-var-bugs: \\e4d0;\n$fa-var-rupee-sign: \\f156;\n$fa-var-rupee: \\f156;\n$fa-var-file-image: \\f1c5;\n$fa-var-circle-question: \\f059;\n$fa-var-question-circle: \\f059;\n$fa-var-plane-departure: \\f5b0;\n$fa-var-handshake-slash: \\e060;\n$fa-var-book-bookmark: \\e0bb;\n$fa-var-code-branch: \\f126;\n$fa-var-hat-cowboy: \\f8c0;\n$fa-var-bridge: \\e4c8;\n$fa-var-phone-flip: \\f879;\n$fa-var-phone-alt: \\f879;\n$fa-var-truck-front: \\e2b7;\n$fa-var-cat: \\f6be;\n$fa-var-anchor-circle-exclamation: \\e4ab;\n$fa-var-truck-field: \\e58d;\n$fa-var-route: \\f4d7;\n$fa-var-clipboard-question: \\e4e3;\n$fa-var-panorama: \\e209;\n$fa-var-comment-medical: \\f7f5;\n$fa-var-teeth-open: \\f62f;\n$fa-var-file-circle-minus: \\e4ed;\n$fa-var-tags: \\f02c;\n$fa-var-wine-glass: \\f4e3;\n$fa-var-forward-fast: \\f050;\n$fa-var-fast-forward: \\f050;\n$fa-var-face-meh-blank: \\f5a4;\n$fa-var-meh-blank: \\f5a4;\n$fa-var-square-parking: \\f540;\n$fa-var-parking: \\f540;\n$fa-var-house-signal: \\e012;\n$fa-var-bars-progress: \\f828;\n$fa-var-tasks-alt: \\f828;\n$fa-var-faucet-drip: \\e006;\n$fa-var-cart-flatbed: \\f474;\n$fa-var-dolly-flatbed: \\f474;\n$fa-var-ban-smoking: \\f54d;\n$fa-var-smoking-ban: \\f54d;\n$fa-var-terminal: \\f120;\n$fa-var-mobile-button: \\f10b;\n$fa-var-house-medical-flag: \\e514;\n$fa-var-basket-shopping: \\f291;\n$fa-var-shopping-basket: \\f291;\n$fa-var-tape: \\f4db;\n$fa-var-bus-simple: \\f55e;\n$fa-var-bus-alt: \\f55e;\n$fa-var-eye: \\f06e;\n$fa-var-face-sad-cry: \\f5b3;\n$fa-var-sad-cry: \\f5b3;\n$fa-var-audio-description: \\f29e;\n$fa-var-person-military-to-person: \\e54c;\n$fa-var-file-shield: \\e4f0;\n$fa-var-user-slash: \\f506;\n$fa-var-pen: \\f304;\n$fa-var-tower-observation: \\e586;\n$fa-var-file-code: \\f1c9;\n$fa-var-signal: \\f012;\n$fa-var-signal-5: \\f012;\n$fa-var-signal-perfect: \\f012;\n$fa-var-bus: \\f207;\n$fa-var-heart-circle-xmark: \\e501;\n$fa-var-house-chimney: \\e3af;\n$fa-var-home-lg: \\e3af;\n$fa-var-window-maximize: \\f2d0;\n$fa-var-face-frown: \\f119;\n$fa-var-frown: \\f119;\n$fa-var-prescription: \\f5b1;\n$fa-var-shop: \\f54f;\n$fa-var-store-alt: \\f54f;\n$fa-var-floppy-disk: \\f0c7;\n$fa-var-save: \\f0c7;\n$fa-var-vihara: \\f6a7;\n$fa-var-scale-unbalanced: \\f515;\n$fa-var-balance-scale-left: \\f515;\n$fa-var-sort-up: \\f0de;\n$fa-var-sort-asc: \\f0de;\n$fa-var-comment-dots: \\f4ad;\n$fa-var-commenting: \\f4ad;\n$fa-var-plant-wilt: \\e5aa;\n$fa-var-diamond: \\f219;\n$fa-var-face-grin-squint: \\f585;\n$fa-var-grin-squint: \\f585;\n$fa-var-hand-holding-dollar: \\f4c0;\n$fa-var-hand-holding-usd: \\f4c0;\n$fa-var-chart-diagram: \\e695;\n$fa-var-bacterium: \\e05a;\n$fa-var-hand-pointer: \\f25a;\n$fa-var-drum-steelpan: \\f56a;\n$fa-var-hand-scissors: \\f257;\n$fa-var-hands-praying: \\f684;\n$fa-var-praying-hands: \\f684;\n$fa-var-arrow-rotate-right: \\f01e;\n$fa-var-arrow-right-rotate: \\f01e;\n$fa-var-arrow-rotate-forward: \\f01e;\n$fa-var-redo: \\f01e;\n$fa-var-biohazard: \\f780;\n$fa-var-location-crosshairs: \\f601;\n$fa-var-location: \\f601;\n$fa-var-mars-double: \\f227;\n$fa-var-child-dress: \\e59c;\n$fa-var-users-between-lines: \\e591;\n$fa-var-lungs-virus: \\e067;\n$fa-var-face-grin-tears: \\f588;\n$fa-var-grin-tears: \\f588;\n$fa-var-phone: \\f095;\n$fa-var-calendar-xmark: \\f273;\n$fa-var-calendar-times: \\f273;\n$fa-var-child-reaching: \\e59d;\n$fa-var-head-side-virus: \\e064;\n$fa-var-user-gear: \\f4fe;\n$fa-var-user-cog: \\f4fe;\n$fa-var-arrow-up-1-9: \\f163;\n$fa-var-sort-numeric-up: \\f163;\n$fa-var-door-closed: \\f52a;\n$fa-var-shield-virus: \\e06c;\n$fa-var-dice-six: \\f526;\n$fa-var-mosquito-net: \\e52c;\n$fa-var-file-fragment: \\e697;\n$fa-var-bridge-water: \\e4ce;\n$fa-var-person-booth: \\f756;\n$fa-var-text-width: \\f035;\n$fa-var-hat-wizard: \\f6e8;\n$fa-var-pen-fancy: \\f5ac;\n$fa-var-person-digging: \\f85e;\n$fa-var-digging: \\f85e;\n$fa-var-trash: \\f1f8;\n$fa-var-gauge-simple: \\f629;\n$fa-var-gauge-simple-med: \\f629;\n$fa-var-tachometer-average: \\f629;\n$fa-var-book-medical: \\f7e6;\n$fa-var-poo: \\f2fe;\n$fa-var-quote-right: \\f10e;\n$fa-var-quote-right-alt: \\f10e;\n$fa-var-shirt: \\f553;\n$fa-var-t-shirt: \\f553;\n$fa-var-tshirt: \\f553;\n$fa-var-cubes: \\f1b3;\n$fa-var-divide: \\f529;\n$fa-var-tenge-sign: \\f7d7;\n$fa-var-tenge: \\f7d7;\n$fa-var-headphones: \\f025;\n$fa-var-hands-holding: \\f4c2;\n$fa-var-hands-clapping: \\e1a8;\n$fa-var-republican: \\f75e;\n$fa-var-arrow-left: \\f060;\n$fa-var-person-circle-xmark: \\e543;\n$fa-var-ruler: \\f545;\n$fa-var-align-left: \\f036;\n$fa-var-dice-d6: \\f6d1;\n$fa-var-restroom: \\f7bd;\n$fa-var-j: \\4a;\n$fa-var-users-viewfinder: \\e595;\n$fa-var-file-video: \\f1c8;\n$fa-var-up-right-from-square: \\f35d;\n$fa-var-external-link-alt: \\f35d;\n$fa-var-table-cells: \\f00a;\n$fa-var-th: \\f00a;\n$fa-var-file-pdf: \\f1c1;\n$fa-var-book-bible: \\f647;\n$fa-var-bible: \\f647;\n$fa-var-o: \\4f;\n$fa-var-suitcase-medical: \\f0fa;\n$fa-var-medkit: \\f0fa;\n$fa-var-user-secret: \\f21b;\n$fa-var-otter: \\f700;\n$fa-var-person-dress: \\f182;\n$fa-var-female: \\f182;\n$fa-var-comment-dollar: \\f651;\n$fa-var-business-time: \\f64a;\n$fa-var-briefcase-clock: \\f64a;\n$fa-var-table-cells-large: \\f009;\n$fa-var-th-large: \\f009;\n$fa-var-book-tanakh: \\f827;\n$fa-var-tanakh: \\f827;\n$fa-var-phone-volume: \\f2a0;\n$fa-var-volume-control-phone: \\f2a0;\n$fa-var-hat-cowboy-side: \\f8c1;\n$fa-var-clipboard-user: \\f7f3;\n$fa-var-child: \\f1ae;\n$fa-var-lira-sign: \\f195;\n$fa-var-satellite: \\f7bf;\n$fa-var-plane-lock: \\e558;\n$fa-var-tag: \\f02b;\n$fa-var-comment: \\f075;\n$fa-var-cake-candles: \\f1fd;\n$fa-var-birthday-cake: \\f1fd;\n$fa-var-cake: \\f1fd;\n$fa-var-envelope: \\f0e0;\n$fa-var-angles-up: \\f102;\n$fa-var-angle-double-up: \\f102;\n$fa-var-paperclip: \\f0c6;\n$fa-var-arrow-right-to-city: \\e4b3;\n$fa-var-ribbon: \\f4d6;\n$fa-var-lungs: \\f604;\n$fa-var-arrow-up-9-1: \\f887;\n$fa-var-sort-numeric-up-alt: \\f887;\n$fa-var-litecoin-sign: \\e1d3;\n$fa-var-border-none: \\f850;\n$fa-var-circle-nodes: \\e4e2;\n$fa-var-parachute-box: \\f4cd;\n$fa-var-indent: \\f03c;\n$fa-var-truck-field-un: \\e58e;\n$fa-var-hourglass: \\f254;\n$fa-var-hourglass-empty: \\f254;\n$fa-var-mountain: \\f6fc;\n$fa-var-user-doctor: \\f0f0;\n$fa-var-user-md: \\f0f0;\n$fa-var-circle-info: \\f05a;\n$fa-var-info-circle: \\f05a;\n$fa-var-cloud-meatball: \\f73b;\n$fa-var-camera: \\f030;\n$fa-var-camera-alt: \\f030;\n$fa-var-square-virus: \\e578;\n$fa-var-meteor: \\f753;\n$fa-var-car-on: \\e4dd;\n$fa-var-sleigh: \\f7cc;\n$fa-var-arrow-down-1-9: \\f162;\n$fa-var-sort-numeric-asc: \\f162;\n$fa-var-sort-numeric-down: \\f162;\n$fa-var-hand-holding-droplet: \\f4c1;\n$fa-var-hand-holding-water: \\f4c1;\n$fa-var-water: \\f773;\n$fa-var-calendar-check: \\f274;\n$fa-var-braille: \\f2a1;\n$fa-var-prescription-bottle-medical: \\f486;\n$fa-var-prescription-bottle-alt: \\f486;\n$fa-var-landmark: \\f66f;\n$fa-var-truck: \\f0d1;\n$fa-var-crosshairs: \\f05b;\n$fa-var-person-cane: \\e53c;\n$fa-var-tent: \\e57d;\n$fa-var-vest-patches: \\e086;\n$fa-var-check-double: \\f560;\n$fa-var-arrow-down-a-z: \\f15d;\n$fa-var-sort-alpha-asc: \\f15d;\n$fa-var-sort-alpha-down: \\f15d;\n$fa-var-money-bill-wheat: \\e52a;\n$fa-var-cookie: \\f563;\n$fa-var-arrow-rotate-left: \\f0e2;\n$fa-var-arrow-left-rotate: \\f0e2;\n$fa-var-arrow-rotate-back: \\f0e2;\n$fa-var-arrow-rotate-backward: \\f0e2;\n$fa-var-undo: \\f0e2;\n$fa-var-hard-drive: \\f0a0;\n$fa-var-hdd: \\f0a0;\n$fa-var-face-grin-squint-tears: \\f586;\n$fa-var-grin-squint-tears: \\f586;\n$fa-var-dumbbell: \\f44b;\n$fa-var-rectangle-list: \\f022;\n$fa-var-list-alt: \\f022;\n$fa-var-tarp-droplet: \\e57c;\n$fa-var-house-medical-circle-check: \\e511;\n$fa-var-person-skiing-nordic: \\f7ca;\n$fa-var-skiing-nordic: \\f7ca;\n$fa-var-calendar-plus: \\f271;\n$fa-var-plane-arrival: \\f5af;\n$fa-var-circle-left: \\f359;\n$fa-var-arrow-alt-circle-left: \\f359;\n$fa-var-train-subway: \\f239;\n$fa-var-subway: \\f239;\n$fa-var-chart-gantt: \\e0e4;\n$fa-var-indian-rupee-sign: \\e1bc;\n$fa-var-indian-rupee: \\e1bc;\n$fa-var-inr: \\e1bc;\n$fa-var-crop-simple: \\f565;\n$fa-var-crop-alt: \\f565;\n$fa-var-money-bill-1: \\f3d1;\n$fa-var-money-bill-alt: \\f3d1;\n$fa-var-left-long: \\f30a;\n$fa-var-long-arrow-alt-left: \\f30a;\n$fa-var-dna: \\f471;\n$fa-var-virus-slash: \\e075;\n$fa-var-minus: \\f068;\n$fa-var-subtract: \\f068;\n$fa-var-chess: \\f439;\n$fa-var-arrow-left-long: \\f177;\n$fa-var-long-arrow-left: \\f177;\n$fa-var-plug-circle-check: \\e55c;\n$fa-var-street-view: \\f21d;\n$fa-var-franc-sign: \\e18f;\n$fa-var-volume-off: \\f026;\n$fa-var-hands-asl-interpreting: \\f2a3;\n$fa-var-american-sign-language-interpreting: \\f2a3;\n$fa-var-asl-interpreting: \\f2a3;\n$fa-var-hands-american-sign-language-interpreting: \\f2a3;\n$fa-var-gear: \\f013;\n$fa-var-cog: \\f013;\n$fa-var-droplet-slash: \\f5c7;\n$fa-var-tint-slash: \\f5c7;\n$fa-var-mosque: \\f678;\n$fa-var-mosquito: \\e52b;\n$fa-var-star-of-david: \\f69a;\n$fa-var-person-military-rifle: \\e54b;\n$fa-var-cart-shopping: \\f07a;\n$fa-var-shopping-cart: \\f07a;\n$fa-var-vials: \\f493;\n$fa-var-plug-circle-plus: \\e55f;\n$fa-var-place-of-worship: \\f67f;\n$fa-var-grip-vertical: \\f58e;\n$fa-var-hexagon-nodes: \\e699;\n$fa-var-arrow-turn-up: \\f148;\n$fa-var-level-up: \\f148;\n$fa-var-u: \\55;\n$fa-var-square-root-variable: \\f698;\n$fa-var-square-root-alt: \\f698;\n$fa-var-clock: \\f017;\n$fa-var-clock-four: \\f017;\n$fa-var-backward-step: \\f048;\n$fa-var-step-backward: \\f048;\n$fa-var-pallet: \\f482;\n$fa-var-faucet: \\e005;\n$fa-var-baseball-bat-ball: \\f432;\n$fa-var-s: \\53;\n$fa-var-timeline: \\e29c;\n$fa-var-keyboard: \\f11c;\n$fa-var-caret-down: \\f0d7;\n$fa-var-house-chimney-medical: \\f7f2;\n$fa-var-clinic-medical: \\f7f2;\n$fa-var-temperature-three-quarters: \\f2c8;\n$fa-var-temperature-3: \\f2c8;\n$fa-var-thermometer-3: \\f2c8;\n$fa-var-thermometer-three-quarters: \\f2c8;\n$fa-var-mobile-screen: \\f3cf;\n$fa-var-mobile-android-alt: \\f3cf;\n$fa-var-plane-up: \\e22d;\n$fa-var-piggy-bank: \\f4d3;\n$fa-var-battery-half: \\f242;\n$fa-var-battery-3: \\f242;\n$fa-var-mountain-city: \\e52e;\n$fa-var-coins: \\f51e;\n$fa-var-khanda: \\f66d;\n$fa-var-sliders: \\f1de;\n$fa-var-sliders-h: \\f1de;\n$fa-var-folder-tree: \\f802;\n$fa-var-network-wired: \\f6ff;\n$fa-var-map-pin: \\f276;\n$fa-var-hamsa: \\f665;\n$fa-var-cent-sign: \\e3f5;\n$fa-var-flask: \\f0c3;\n$fa-var-person-pregnant: \\e31e;\n$fa-var-wand-sparkles: \\f72b;\n$fa-var-ellipsis-vertical: \\f142;\n$fa-var-ellipsis-v: \\f142;\n$fa-var-ticket: \\f145;\n$fa-var-power-off: \\f011;\n$fa-var-right-long: \\f30b;\n$fa-var-long-arrow-alt-right: \\f30b;\n$fa-var-flag-usa: \\f74d;\n$fa-var-laptop-file: \\e51d;\n$fa-var-tty: \\f1e4;\n$fa-var-teletype: \\f1e4;\n$fa-var-diagram-next: \\e476;\n$fa-var-person-rifle: \\e54e;\n$fa-var-house-medical-circle-exclamation: \\e512;\n$fa-var-closed-captioning: \\f20a;\n$fa-var-person-hiking: \\f6ec;\n$fa-var-hiking: \\f6ec;\n$fa-var-venus-double: \\f226;\n$fa-var-images: \\f302;\n$fa-var-calculator: \\f1ec;\n$fa-var-people-pulling: \\e535;\n$fa-var-n: \\4e;\n$fa-var-cable-car: \\f7da;\n$fa-var-tram: \\f7da;\n$fa-var-cloud-rain: \\f73d;\n$fa-var-building-circle-xmark: \\e4d4;\n$fa-var-ship: \\f21a;\n$fa-var-arrows-down-to-line: \\e4b8;\n$fa-var-download: \\f019;\n$fa-var-face-grin: \\f580;\n$fa-var-grin: \\f580;\n$fa-var-delete-left: \\f55a;\n$fa-var-backspace: \\f55a;\n$fa-var-eye-dropper: \\f1fb;\n$fa-var-eye-dropper-empty: \\f1fb;\n$fa-var-eyedropper: \\f1fb;\n$fa-var-file-circle-check: \\e5a0;\n$fa-var-forward: \\f04e;\n$fa-var-mobile: \\f3ce;\n$fa-var-mobile-android: \\f3ce;\n$fa-var-mobile-phone: \\f3ce;\n$fa-var-face-meh: \\f11a;\n$fa-var-meh: \\f11a;\n$fa-var-align-center: \\f037;\n$fa-var-book-skull: \\f6b7;\n$fa-var-book-dead: \\f6b7;\n$fa-var-id-card: \\f2c2;\n$fa-var-drivers-license: \\f2c2;\n$fa-var-outdent: \\f03b;\n$fa-var-dedent: \\f03b;\n$fa-var-heart-circle-exclamation: \\e4fe;\n$fa-var-house: \\f015;\n$fa-var-home: \\f015;\n$fa-var-home-alt: \\f015;\n$fa-var-home-lg-alt: \\f015;\n$fa-var-calendar-week: \\f784;\n$fa-var-laptop-medical: \\f812;\n$fa-var-b: \\42;\n$fa-var-file-medical: \\f477;\n$fa-var-dice-one: \\f525;\n$fa-var-kiwi-bird: \\f535;\n$fa-var-arrow-right-arrow-left: \\f0ec;\n$fa-var-exchange: \\f0ec;\n$fa-var-rotate-right: \\f2f9;\n$fa-var-redo-alt: \\f2f9;\n$fa-var-rotate-forward: \\f2f9;\n$fa-var-utensils: \\f2e7;\n$fa-var-cutlery: \\f2e7;\n$fa-var-arrow-up-wide-short: \\f161;\n$fa-var-sort-amount-up: \\f161;\n$fa-var-mill-sign: \\e1ed;\n$fa-var-bowl-rice: \\e2eb;\n$fa-var-skull: \\f54c;\n$fa-var-tower-broadcast: \\f519;\n$fa-var-broadcast-tower: \\f519;\n$fa-var-truck-pickup: \\f63c;\n$fa-var-up-long: \\f30c;\n$fa-var-long-arrow-alt-up: \\f30c;\n$fa-var-stop: \\f04d;\n$fa-var-code-merge: \\f387;\n$fa-var-upload: \\f093;\n$fa-var-hurricane: \\f751;\n$fa-var-mound: \\e52d;\n$fa-var-toilet-portable: \\e583;\n$fa-var-compact-disc: \\f51f;\n$fa-var-file-arrow-down: \\f56d;\n$fa-var-file-download: \\f56d;\n$fa-var-caravan: \\f8ff;\n$fa-var-shield-cat: \\e572;\n$fa-var-bolt: \\f0e7;\n$fa-var-zap: \\f0e7;\n$fa-var-glass-water: \\e4f4;\n$fa-var-oil-well: \\e532;\n$fa-var-vault: \\e2c5;\n$fa-var-mars: \\f222;\n$fa-var-toilet: \\f7d8;\n$fa-var-plane-circle-xmark: \\e557;\n$fa-var-yen-sign: \\f157;\n$fa-var-cny: \\f157;\n$fa-var-jpy: \\f157;\n$fa-var-rmb: \\f157;\n$fa-var-yen: \\f157;\n$fa-var-ruble-sign: \\f158;\n$fa-var-rouble: \\f158;\n$fa-var-rub: \\f158;\n$fa-var-ruble: \\f158;\n$fa-var-sun: \\f185;\n$fa-var-guitar: \\f7a6;\n$fa-var-face-laugh-wink: \\f59c;\n$fa-var-laugh-wink: \\f59c;\n$fa-var-horse-head: \\f7ab;\n$fa-var-bore-hole: \\e4c3;\n$fa-var-industry: \\f275;\n$fa-var-circle-down: \\f358;\n$fa-var-arrow-alt-circle-down: \\f358;\n$fa-var-arrows-turn-to-dots: \\e4c1;\n$fa-var-florin-sign: \\e184;\n$fa-var-arrow-down-short-wide: \\f884;\n$fa-var-sort-amount-desc: \\f884;\n$fa-var-sort-amount-down-alt: \\f884;\n$fa-var-less-than: \\3c;\n$fa-var-angle-down: \\f107;\n$fa-var-car-tunnel: \\e4de;\n$fa-var-head-side-cough: \\e061;\n$fa-var-grip-lines: \\f7a4;\n$fa-var-thumbs-down: \\f165;\n$fa-var-user-lock: \\f502;\n$fa-var-arrow-right-long: \\f178;\n$fa-var-long-arrow-right: \\f178;\n$fa-var-anchor-circle-xmark: \\e4ac;\n$fa-var-ellipsis: \\f141;\n$fa-var-ellipsis-h: \\f141;\n$fa-var-chess-pawn: \\f443;\n$fa-var-kit-medical: \\f479;\n$fa-var-first-aid: \\f479;\n$fa-var-person-through-window: \\e5a9;\n$fa-var-toolbox: \\f552;\n$fa-var-hands-holding-circle: \\e4fb;\n$fa-var-bug: \\f188;\n$fa-var-credit-card: \\f09d;\n$fa-var-credit-card-alt: \\f09d;\n$fa-var-car: \\f1b9;\n$fa-var-automobile: \\f1b9;\n$fa-var-hand-holding-hand: \\e4f7;\n$fa-var-book-open-reader: \\f5da;\n$fa-var-book-reader: \\f5da;\n$fa-var-mountain-sun: \\e52f;\n$fa-var-arrows-left-right-to-line: \\e4ba;\n$fa-var-dice-d20: \\f6cf;\n$fa-var-truck-droplet: \\e58c;\n$fa-var-file-circle-xmark: \\e5a1;\n$fa-var-temperature-arrow-up: \\e040;\n$fa-var-temperature-up: \\e040;\n$fa-var-medal: \\f5a2;\n$fa-var-bed: \\f236;\n$fa-var-square-h: \\f0fd;\n$fa-var-h-square: \\f0fd;\n$fa-var-podcast: \\f2ce;\n$fa-var-temperature-full: \\f2c7;\n$fa-var-temperature-4: \\f2c7;\n$fa-var-thermometer-4: \\f2c7;\n$fa-var-thermometer-full: \\f2c7;\n$fa-var-bell: \\f0f3;\n$fa-var-superscript: \\f12b;\n$fa-var-plug-circle-xmark: \\e560;\n$fa-var-star-of-life: \\f621;\n$fa-var-phone-slash: \\f3dd;\n$fa-var-paint-roller: \\f5aa;\n$fa-var-handshake-angle: \\f4c4;\n$fa-var-hands-helping: \\f4c4;\n$fa-var-location-dot: \\f3c5;\n$fa-var-map-marker-alt: \\f3c5;\n$fa-var-file: \\f15b;\n$fa-var-greater-than: \\3e;\n$fa-var-person-swimming: \\f5c4;\n$fa-var-swimmer: \\f5c4;\n$fa-var-arrow-down: \\f063;\n$fa-var-droplet: \\f043;\n$fa-var-tint: \\f043;\n$fa-var-eraser: \\f12d;\n$fa-var-earth-americas: \\f57d;\n$fa-var-earth: \\f57d;\n$fa-var-earth-america: \\f57d;\n$fa-var-globe-americas: \\f57d;\n$fa-var-person-burst: \\e53b;\n$fa-var-dove: \\f4ba;\n$fa-var-battery-empty: \\f244;\n$fa-var-battery-0: \\f244;\n$fa-var-socks: \\f696;\n$fa-var-inbox: \\f01c;\n$fa-var-section: \\e447;\n$fa-var-gauge-high: \\f625;\n$fa-var-tachometer-alt: \\f625;\n$fa-var-tachometer-alt-fast: \\f625;\n$fa-var-envelope-open-text: \\f658;\n$fa-var-hospital: \\f0f8;\n$fa-var-hospital-alt: \\f0f8;\n$fa-var-hospital-wide: \\f0f8;\n$fa-var-wine-bottle: \\f72f;\n$fa-var-chess-rook: \\f447;\n$fa-var-bars-staggered: \\f550;\n$fa-var-reorder: \\f550;\n$fa-var-stream: \\f550;\n$fa-var-dharmachakra: \\f655;\n$fa-var-hotdog: \\f80f;\n$fa-var-person-walking-with-cane: \\f29d;\n$fa-var-blind: \\f29d;\n$fa-var-drum: \\f569;\n$fa-var-ice-cream: \\f810;\n$fa-var-heart-circle-bolt: \\e4fc;\n$fa-var-fax: \\f1ac;\n$fa-var-paragraph: \\f1dd;\n$fa-var-check-to-slot: \\f772;\n$fa-var-vote-yea: \\f772;\n$fa-var-star-half: \\f089;\n$fa-var-boxes-stacked: \\f468;\n$fa-var-boxes: \\f468;\n$fa-var-boxes-alt: \\f468;\n$fa-var-link: \\f0c1;\n$fa-var-chain: \\f0c1;\n$fa-var-ear-listen: \\f2a2;\n$fa-var-assistive-listening-systems: \\f2a2;\n$fa-var-tree-city: \\e587;\n$fa-var-play: \\f04b;\n$fa-var-font: \\f031;\n$fa-var-table-cells-row-lock: \\e67a;\n$fa-var-rupiah-sign: \\e23d;\n$fa-var-magnifying-glass: \\f002;\n$fa-var-search: \\f002;\n$fa-var-table-tennis-paddle-ball: \\f45d;\n$fa-var-ping-pong-paddle-ball: \\f45d;\n$fa-var-table-tennis: \\f45d;\n$fa-var-person-dots-from-line: \\f470;\n$fa-var-diagnoses: \\f470;\n$fa-var-trash-can-arrow-up: \\f82a;\n$fa-var-trash-restore-alt: \\f82a;\n$fa-var-naira-sign: \\e1f6;\n$fa-var-cart-arrow-down: \\f218;\n$fa-var-walkie-talkie: \\f8ef;\n$fa-var-file-pen: \\f31c;\n$fa-var-file-edit: \\f31c;\n$fa-var-receipt: \\f543;\n$fa-var-square-pen: \\f14b;\n$fa-var-pen-square: \\f14b;\n$fa-var-pencil-square: \\f14b;\n$fa-var-suitcase-rolling: \\f5c1;\n$fa-var-person-circle-exclamation: \\e53f;\n$fa-var-chevron-down: \\f078;\n$fa-var-battery-full: \\f240;\n$fa-var-battery: \\f240;\n$fa-var-battery-5: \\f240;\n$fa-var-skull-crossbones: \\f714;\n$fa-var-code-compare: \\e13a;\n$fa-var-list-ul: \\f0ca;\n$fa-var-list-dots: \\f0ca;\n$fa-var-school-lock: \\e56f;\n$fa-var-tower-cell: \\e585;\n$fa-var-down-long: \\f309;\n$fa-var-long-arrow-alt-down: \\f309;\n$fa-var-ranking-star: \\e561;\n$fa-var-chess-king: \\f43f;\n$fa-var-person-harassing: \\e549;\n$fa-var-brazilian-real-sign: \\e46c;\n$fa-var-landmark-dome: \\f752;\n$fa-var-landmark-alt: \\f752;\n$fa-var-arrow-up: \\f062;\n$fa-var-tv: \\f26c;\n$fa-var-television: \\f26c;\n$fa-var-tv-alt: \\f26c;\n$fa-var-shrimp: \\e448;\n$fa-var-list-check: \\f0ae;\n$fa-var-tasks: \\f0ae;\n$fa-var-jug-detergent: \\e519;\n$fa-var-circle-user: \\f2bd;\n$fa-var-user-circle: \\f2bd;\n$fa-var-user-shield: \\f505;\n$fa-var-wind: \\f72e;\n$fa-var-car-burst: \\f5e1;\n$fa-var-car-crash: \\f5e1;\n$fa-var-y: \\59;\n$fa-var-person-snowboarding: \\f7ce;\n$fa-var-snowboarding: \\f7ce;\n$fa-var-truck-fast: \\f48b;\n$fa-var-shipping-fast: \\f48b;\n$fa-var-fish: \\f578;\n$fa-var-user-graduate: \\f501;\n$fa-var-circle-half-stroke: \\f042;\n$fa-var-adjust: \\f042;\n$fa-var-clapperboard: \\e131;\n$fa-var-circle-radiation: \\f7ba;\n$fa-var-radiation-alt: \\f7ba;\n$fa-var-baseball: \\f433;\n$fa-var-baseball-ball: \\f433;\n$fa-var-jet-fighter-up: \\e518;\n$fa-var-diagram-project: \\f542;\n$fa-var-project-diagram: \\f542;\n$fa-var-copy: \\f0c5;\n$fa-var-volume-xmark: \\f6a9;\n$fa-var-volume-mute: \\f6a9;\n$fa-var-volume-times: \\f6a9;\n$fa-var-hand-sparkles: \\e05d;\n$fa-var-grip: \\f58d;\n$fa-var-grip-horizontal: \\f58d;\n$fa-var-share-from-square: \\f14d;\n$fa-var-share-square: \\f14d;\n$fa-var-child-combatant: \\e4e0;\n$fa-var-child-rifle: \\e4e0;\n$fa-var-gun: \\e19b;\n$fa-var-square-phone: \\f098;\n$fa-var-phone-square: \\f098;\n$fa-var-plus: \\2b;\n$fa-var-add: \\2b;\n$fa-var-expand: \\f065;\n$fa-var-computer: \\e4e5;\n$fa-var-xmark: \\f00d;\n$fa-var-close: \\f00d;\n$fa-var-multiply: \\f00d;\n$fa-var-remove: \\f00d;\n$fa-var-times: \\f00d;\n$fa-var-arrows-up-down-left-right: \\f047;\n$fa-var-arrows: \\f047;\n$fa-var-chalkboard-user: \\f51c;\n$fa-var-chalkboard-teacher: \\f51c;\n$fa-var-peso-sign: \\e222;\n$fa-var-building-shield: \\e4d8;\n$fa-var-baby: \\f77c;\n$fa-var-users-line: \\e592;\n$fa-var-quote-left: \\f10d;\n$fa-var-quote-left-alt: \\f10d;\n$fa-var-tractor: \\f722;\n$fa-var-trash-arrow-up: \\f829;\n$fa-var-trash-restore: \\f829;\n$fa-var-arrow-down-up-lock: \\e4b0;\n$fa-var-lines-leaning: \\e51e;\n$fa-var-ruler-combined: \\f546;\n$fa-var-copyright: \\f1f9;\n$fa-var-equals: \\3d;\n$fa-var-blender: \\f517;\n$fa-var-teeth: \\f62e;\n$fa-var-shekel-sign: \\f20b;\n$fa-var-ils: \\f20b;\n$fa-var-shekel: \\f20b;\n$fa-var-sheqel: \\f20b;\n$fa-var-sheqel-sign: \\f20b;\n$fa-var-map: \\f279;\n$fa-var-rocket: \\f135;\n$fa-var-photo-film: \\f87c;\n$fa-var-photo-video: \\f87c;\n$fa-var-folder-minus: \\f65d;\n$fa-var-hexagon-nodes-bolt: \\e69a;\n$fa-var-store: \\f54e;\n$fa-var-arrow-trend-up: \\e098;\n$fa-var-plug-circle-minus: \\e55e;\n$fa-var-sign-hanging: \\f4d9;\n$fa-var-sign: \\f4d9;\n$fa-var-bezier-curve: \\f55b;\n$fa-var-bell-slash: \\f1f6;\n$fa-var-tablet: \\f3fb;\n$fa-var-tablet-android: \\f3fb;\n$fa-var-school-flag: \\e56e;\n$fa-var-fill: \\f575;\n$fa-var-angle-up: \\f106;\n$fa-var-drumstick-bite: \\f6d7;\n$fa-var-holly-berry: \\f7aa;\n$fa-var-chevron-left: \\f053;\n$fa-var-bacteria: \\e059;\n$fa-var-hand-lizard: \\f258;\n$fa-var-notdef: \\e1fe;\n$fa-var-disease: \\f7fa;\n$fa-var-briefcase-medical: \\f469;\n$fa-var-genderless: \\f22d;\n$fa-var-chevron-right: \\f054;\n$fa-var-retweet: \\f079;\n$fa-var-car-rear: \\f5de;\n$fa-var-car-alt: \\f5de;\n$fa-var-pump-soap: \\e06b;\n$fa-var-video-slash: \\f4e2;\n$fa-var-battery-quarter: \\f243;\n$fa-var-battery-2: \\f243;\n$fa-var-radio: \\f8d7;\n$fa-var-baby-carriage: \\f77d;\n$fa-var-carriage-baby: \\f77d;\n$fa-var-traffic-light: \\f637;\n$fa-var-thermometer: \\f491;\n$fa-var-vr-cardboard: \\f729;\n$fa-var-hand-middle-finger: \\f806;\n$fa-var-percent: \\25;\n$fa-var-percentage: \\25;\n$fa-var-truck-moving: \\f4df;\n$fa-var-glass-water-droplet: \\e4f5;\n$fa-var-display: \\e163;\n$fa-var-face-smile: \\f118;\n$fa-var-smile: \\f118;\n$fa-var-thumbtack: \\f08d;\n$fa-var-thumb-tack: \\f08d;\n$fa-var-trophy: \\f091;\n$fa-var-person-praying: \\f683;\n$fa-var-pray: \\f683;\n$fa-var-hammer: \\f6e3;\n$fa-var-hand-peace: \\f25b;\n$fa-var-rotate: \\f2f1;\n$fa-var-sync-alt: \\f2f1;\n$fa-var-spinner: \\f110;\n$fa-var-robot: \\f544;\n$fa-var-peace: \\f67c;\n$fa-var-gears: \\f085;\n$fa-var-cogs: \\f085;\n$fa-var-warehouse: \\f494;\n$fa-var-arrow-up-right-dots: \\e4b7;\n$fa-var-splotch: \\f5bc;\n$fa-var-face-grin-hearts: \\f584;\n$fa-var-grin-hearts: \\f584;\n$fa-var-dice-four: \\f524;\n$fa-var-sim-card: \\f7c4;\n$fa-var-transgender: \\f225;\n$fa-var-transgender-alt: \\f225;\n$fa-var-mercury: \\f223;\n$fa-var-arrow-turn-down: \\f149;\n$fa-var-level-down: \\f149;\n$fa-var-person-falling-burst: \\e547;\n$fa-var-award: \\f559;\n$fa-var-ticket-simple: \\f3ff;\n$fa-var-ticket-alt: \\f3ff;\n$fa-var-building: \\f1ad;\n$fa-var-angles-left: \\f100;\n$fa-var-angle-double-left: \\f100;\n$fa-var-qrcode: \\f029;\n$fa-var-clock-rotate-left: \\f1da;\n$fa-var-history: \\f1da;\n$fa-var-face-grin-beam-sweat: \\f583;\n$fa-var-grin-beam-sweat: \\f583;\n$fa-var-file-export: \\f56e;\n$fa-var-arrow-right-from-file: \\f56e;\n$fa-var-shield: \\f132;\n$fa-var-shield-blank: \\f132;\n$fa-var-arrow-up-short-wide: \\f885;\n$fa-var-sort-amount-up-alt: \\f885;\n$fa-var-comment-nodes: \\e696;\n$fa-var-house-medical: \\e3b2;\n$fa-var-golf-ball-tee: \\f450;\n$fa-var-golf-ball: \\f450;\n$fa-var-circle-chevron-left: \\f137;\n$fa-var-chevron-circle-left: \\f137;\n$fa-var-house-chimney-window: \\e00d;\n$fa-var-pen-nib: \\f5ad;\n$fa-var-tent-arrow-turn-left: \\e580;\n$fa-var-tents: \\e582;\n$fa-var-wand-magic: \\f0d0;\n$fa-var-magic: \\f0d0;\n$fa-var-dog: \\f6d3;\n$fa-var-carrot: \\f787;\n$fa-var-moon: \\f186;\n$fa-var-wine-glass-empty: \\f5ce;\n$fa-var-wine-glass-alt: \\f5ce;\n$fa-var-cheese: \\f7ef;\n$fa-var-yin-yang: \\f6ad;\n$fa-var-music: \\f001;\n$fa-var-code-commit: \\f386;\n$fa-var-temperature-low: \\f76b;\n$fa-var-person-biking: \\f84a;\n$fa-var-biking: \\f84a;\n$fa-var-broom: \\f51a;\n$fa-var-shield-heart: \\e574;\n$fa-var-gopuram: \\f664;\n$fa-var-earth-oceania: \\e47b;\n$fa-var-globe-oceania: \\e47b;\n$fa-var-square-xmark: \\f2d3;\n$fa-var-times-square: \\f2d3;\n$fa-var-xmark-square: \\f2d3;\n$fa-var-hashtag: \\23;\n$fa-var-up-right-and-down-left-from-center: \\f424;\n$fa-var-expand-alt: \\f424;\n$fa-var-oil-can: \\f613;\n$fa-var-t: \\54;\n$fa-var-hippo: \\f6ed;\n$fa-var-chart-column: \\e0e3;\n$fa-var-infinity: \\f534;\n$fa-var-vial-circle-check: \\e596;\n$fa-var-person-arrow-down-to-line: \\e538;\n$fa-var-voicemail: \\f897;\n$fa-var-fan: \\f863;\n$fa-var-person-walking-luggage: \\e554;\n$fa-var-up-down: \\f338;\n$fa-var-arrows-alt-v: \\f338;\n$fa-var-cloud-moon-rain: \\f73c;\n$fa-var-calendar: \\f133;\n$fa-var-trailer: \\e041;\n$fa-var-bahai: \\f666;\n$fa-var-haykal: \\f666;\n$fa-var-sd-card: \\f7c2;\n$fa-var-dragon: \\f6d5;\n$fa-var-shoe-prints: \\f54b;\n$fa-var-circle-plus: \\f055;\n$fa-var-plus-circle: \\f055;\n$fa-var-face-grin-tongue-wink: \\f58b;\n$fa-var-grin-tongue-wink: \\f58b;\n$fa-var-hand-holding: \\f4bd;\n$fa-var-plug-circle-exclamation: \\e55d;\n$fa-var-link-slash: \\f127;\n$fa-var-chain-broken: \\f127;\n$fa-var-chain-slash: \\f127;\n$fa-var-unlink: \\f127;\n$fa-var-clone: \\f24d;\n$fa-var-person-walking-arrow-loop-left: \\e551;\n$fa-var-arrow-up-z-a: \\f882;\n$fa-var-sort-alpha-up-alt: \\f882;\n$fa-var-fire-flame-curved: \\f7e4;\n$fa-var-fire-alt: \\f7e4;\n$fa-var-tornado: \\f76f;\n$fa-var-file-circle-plus: \\e494;\n$fa-var-book-quran: \\f687;\n$fa-var-quran: \\f687;\n$fa-var-anchor: \\f13d;\n$fa-var-border-all: \\f84c;\n$fa-var-face-angry: \\f556;\n$fa-var-angry: \\f556;\n$fa-var-cookie-bite: \\f564;\n$fa-var-arrow-trend-down: \\e097;\n$fa-var-rss: \\f09e;\n$fa-var-feed: \\f09e;\n$fa-var-draw-polygon: \\f5ee;\n$fa-var-scale-balanced: \\f24e;\n$fa-var-balance-scale: \\f24e;\n$fa-var-gauge-simple-high: \\f62a;\n$fa-var-tachometer: \\f62a;\n$fa-var-tachometer-fast: \\f62a;\n$fa-var-shower: \\f2cc;\n$fa-var-desktop: \\f390;\n$fa-var-desktop-alt: \\f390;\n$fa-var-m: \\4d;\n$fa-var-table-list: \\f00b;\n$fa-var-th-list: \\f00b;\n$fa-var-comment-sms: \\f7cd;\n$fa-var-sms: \\f7cd;\n$fa-var-book: \\f02d;\n$fa-var-user-plus: \\f234;\n$fa-var-check: \\f00c;\n$fa-var-battery-three-quarters: \\f241;\n$fa-var-battery-4: \\f241;\n$fa-var-house-circle-check: \\e509;\n$fa-var-angle-left: \\f104;\n$fa-var-diagram-successor: \\e47a;\n$fa-var-truck-arrow-right: \\e58b;\n$fa-var-arrows-split-up-and-left: \\e4bc;\n$fa-var-hand-fist: \\f6de;\n$fa-var-fist-raised: \\f6de;\n$fa-var-cloud-moon: \\f6c3;\n$fa-var-briefcase: \\f0b1;\n$fa-var-person-falling: \\e546;\n$fa-var-image-portrait: \\f3e0;\n$fa-var-portrait: \\f3e0;\n$fa-var-user-tag: \\f507;\n$fa-var-rug: \\e569;\n$fa-var-earth-europe: \\f7a2;\n$fa-var-globe-europe: \\f7a2;\n$fa-var-cart-flatbed-suitcase: \\f59d;\n$fa-var-luggage-cart: \\f59d;\n$fa-var-rectangle-xmark: \\f410;\n$fa-var-rectangle-times: \\f410;\n$fa-var-times-rectangle: \\f410;\n$fa-var-window-close: \\f410;\n$fa-var-baht-sign: \\e0ac;\n$fa-var-book-open: \\f518;\n$fa-var-book-journal-whills: \\f66a;\n$fa-var-journal-whills: \\f66a;\n$fa-var-handcuffs: \\e4f8;\n$fa-var-triangle-exclamation: \\f071;\n$fa-var-exclamation-triangle: \\f071;\n$fa-var-warning: \\f071;\n$fa-var-database: \\f1c0;\n$fa-var-share: \\f064;\n$fa-var-mail-forward: \\f064;\n$fa-var-bottle-droplet: \\e4c4;\n$fa-var-mask-face: \\e1d7;\n$fa-var-hill-rockslide: \\e508;\n$fa-var-right-left: \\f362;\n$fa-var-exchange-alt: \\f362;\n$fa-var-paper-plane: \\f1d8;\n$fa-var-road-circle-exclamation: \\e565;\n$fa-var-dungeon: \\f6d9;\n$fa-var-align-right: \\f038;\n$fa-var-money-bill-1-wave: \\f53b;\n$fa-var-money-bill-wave-alt: \\f53b;\n$fa-var-life-ring: \\f1cd;\n$fa-var-hands: \\f2a7;\n$fa-var-sign-language: \\f2a7;\n$fa-var-signing: \\f2a7;\n$fa-var-calendar-day: \\f783;\n$fa-var-water-ladder: \\f5c5;\n$fa-var-ladder-water: \\f5c5;\n$fa-var-swimming-pool: \\f5c5;\n$fa-var-arrows-up-down: \\f07d;\n$fa-var-arrows-v: \\f07d;\n$fa-var-face-grimace: \\f57f;\n$fa-var-grimace: \\f57f;\n$fa-var-wheelchair-move: \\e2ce;\n$fa-var-wheelchair-alt: \\e2ce;\n$fa-var-turn-down: \\f3be;\n$fa-var-level-down-alt: \\f3be;\n$fa-var-person-walking-arrow-right: \\e552;\n$fa-var-square-envelope: \\f199;\n$fa-var-envelope-square: \\f199;\n$fa-var-dice: \\f522;\n$fa-var-bowling-ball: \\f436;\n$fa-var-brain: \\f5dc;\n$fa-var-bandage: \\f462;\n$fa-var-band-aid: \\f462;\n$fa-var-calendar-minus: \\f272;\n$fa-var-circle-xmark: \\f057;\n$fa-var-times-circle: \\f057;\n$fa-var-xmark-circle: \\f057;\n$fa-var-gifts: \\f79c;\n$fa-var-hotel: \\f594;\n$fa-var-earth-asia: \\f57e;\n$fa-var-globe-asia: \\f57e;\n$fa-var-id-card-clip: \\f47f;\n$fa-var-id-card-alt: \\f47f;\n$fa-var-magnifying-glass-plus: \\f00e;\n$fa-var-search-plus: \\f00e;\n$fa-var-thumbs-up: \\f164;\n$fa-var-user-clock: \\f4fd;\n$fa-var-hand-dots: \\f461;\n$fa-var-allergies: \\f461;\n$fa-var-file-invoice: \\f570;\n$fa-var-window-minimize: \\f2d1;\n$fa-var-mug-saucer: \\f0f4;\n$fa-var-coffee: \\f0f4;\n$fa-var-brush: \\f55d;\n$fa-var-file-half-dashed: \\e698;\n$fa-var-mask: \\f6fa;\n$fa-var-magnifying-glass-minus: \\f010;\n$fa-var-search-minus: \\f010;\n$fa-var-ruler-vertical: \\f548;\n$fa-var-user-large: \\f406;\n$fa-var-user-alt: \\f406;\n$fa-var-train-tram: \\e5b4;\n$fa-var-user-nurse: \\f82f;\n$fa-var-syringe: \\f48e;\n$fa-var-cloud-sun: \\f6c4;\n$fa-var-stopwatch-20: \\e06f;\n$fa-var-square-full: \\f45c;\n$fa-var-magnet: \\f076;\n$fa-var-jar: \\e516;\n$fa-var-note-sticky: \\f249;\n$fa-var-sticky-note: \\f249;\n$fa-var-bug-slash: \\e490;\n$fa-var-arrow-up-from-water-pump: \\e4b6;\n$fa-var-bone: \\f5d7;\n$fa-var-table-cells-row-unlock: \\e691;\n$fa-var-user-injured: \\f728;\n$fa-var-face-sad-tear: \\f5b4;\n$fa-var-sad-tear: \\f5b4;\n$fa-var-plane: \\f072;\n$fa-var-tent-arrows-down: \\e581;\n$fa-var-exclamation: \\21;\n$fa-var-arrows-spin: \\e4bb;\n$fa-var-print: \\f02f;\n$fa-var-turkish-lira-sign: \\e2bb;\n$fa-var-try: \\e2bb;\n$fa-var-turkish-lira: \\e2bb;\n$fa-var-dollar-sign: \\24;\n$fa-var-dollar: \\24;\n$fa-var-usd: \\24;\n$fa-var-x: \\58;\n$fa-var-magnifying-glass-dollar: \\f688;\n$fa-var-search-dollar: \\f688;\n$fa-var-users-gear: \\f509;\n$fa-var-users-cog: \\f509;\n$fa-var-person-military-pointing: \\e54a;\n$fa-var-building-columns: \\f19c;\n$fa-var-bank: \\f19c;\n$fa-var-institution: \\f19c;\n$fa-var-museum: \\f19c;\n$fa-var-university: \\f19c;\n$fa-var-umbrella: \\f0e9;\n$fa-var-trowel: \\e589;\n$fa-var-d: \\44;\n$fa-var-stapler: \\e5af;\n$fa-var-masks-theater: \\f630;\n$fa-var-theater-masks: \\f630;\n$fa-var-kip-sign: \\e1c4;\n$fa-var-hand-point-left: \\f0a5;\n$fa-var-handshake-simple: \\f4c6;\n$fa-var-handshake-alt: \\f4c6;\n$fa-var-jet-fighter: \\f0fb;\n$fa-var-fighter-jet: \\f0fb;\n$fa-var-square-share-nodes: \\f1e1;\n$fa-var-share-alt-square: \\f1e1;\n$fa-var-barcode: \\f02a;\n$fa-var-plus-minus: \\e43c;\n$fa-var-video: \\f03d;\n$fa-var-video-camera: \\f03d;\n$fa-var-graduation-cap: \\f19d;\n$fa-var-mortar-board: \\f19d;\n$fa-var-hand-holding-medical: \\e05c;\n$fa-var-person-circle-check: \\e53e;\n$fa-var-turn-up: \\f3bf;\n$fa-var-level-up-alt: \\f3bf;\n\n$fa-var-monero: \\f3d0;\n$fa-var-hooli: \\f427;\n$fa-var-yelp: \\f1e9;\n$fa-var-cc-visa: \\f1f0;\n$fa-var-lastfm: \\f202;\n$fa-var-shopware: \\f5b5;\n$fa-var-creative-commons-nc: \\f4e8;\n$fa-var-aws: \\f375;\n$fa-var-redhat: \\f7bc;\n$fa-var-yoast: \\f2b1;\n$fa-var-cloudflare: \\e07d;\n$fa-var-ups: \\f7e0;\n$fa-var-pixiv: \\e640;\n$fa-var-wpexplorer: \\f2de;\n$fa-var-dyalog: \\f399;\n$fa-var-bity: \\f37a;\n$fa-var-stackpath: \\f842;\n$fa-var-buysellads: \\f20d;\n$fa-var-first-order: \\f2b0;\n$fa-var-modx: \\f285;\n$fa-var-guilded: \\e07e;\n$fa-var-vnv: \\f40b;\n$fa-var-square-js: \\f3b9;\n$fa-var-js-square: \\f3b9;\n$fa-var-microsoft: \\f3ca;\n$fa-var-qq: \\f1d6;\n$fa-var-orcid: \\f8d2;\n$fa-var-java: \\f4e4;\n$fa-var-invision: \\f7b0;\n$fa-var-creative-commons-pd-alt: \\f4ed;\n$fa-var-centercode: \\f380;\n$fa-var-glide-g: \\f2a6;\n$fa-var-drupal: \\f1a9;\n$fa-var-jxl: \\e67b;\n$fa-var-dart-lang: \\e693;\n$fa-var-hire-a-helper: \\f3b0;\n$fa-var-creative-commons-by: \\f4e7;\n$fa-var-unity: \\e049;\n$fa-var-whmcs: \\f40d;\n$fa-var-rocketchat: \\f3e8;\n$fa-var-vk: \\f189;\n$fa-var-untappd: \\f405;\n$fa-var-mailchimp: \\f59e;\n$fa-var-css3-alt: \\f38b;\n$fa-var-square-reddit: \\f1a2;\n$fa-var-reddit-square: \\f1a2;\n$fa-var-vimeo-v: \\f27d;\n$fa-var-contao: \\f26d;\n$fa-var-square-font-awesome: \\e5ad;\n$fa-var-deskpro: \\f38f;\n$fa-var-brave: \\e63c;\n$fa-var-sistrix: \\f3ee;\n$fa-var-square-instagram: \\e055;\n$fa-var-instagram-square: \\e055;\n$fa-var-battle-net: \\f835;\n$fa-var-the-red-yeti: \\f69d;\n$fa-var-square-hacker-news: \\f3af;\n$fa-var-hacker-news-square: \\f3af;\n$fa-var-edge: \\f282;\n$fa-var-threads: \\e618;\n$fa-var-napster: \\f3d2;\n$fa-var-square-snapchat: \\f2ad;\n$fa-var-snapchat-square: \\f2ad;\n$fa-var-google-plus-g: \\f0d5;\n$fa-var-artstation: \\f77a;\n$fa-var-markdown: \\f60f;\n$fa-var-sourcetree: \\f7d3;\n$fa-var-google-plus: \\f2b3;\n$fa-var-diaspora: \\f791;\n$fa-var-foursquare: \\f180;\n$fa-var-stack-overflow: \\f16c;\n$fa-var-github-alt: \\f113;\n$fa-var-phoenix-squadron: \\f511;\n$fa-var-pagelines: \\f18c;\n$fa-var-algolia: \\f36c;\n$fa-var-red-river: \\f3e3;\n$fa-var-creative-commons-sa: \\f4ef;\n$fa-var-safari: \\f267;\n$fa-var-google: \\f1a0;\n$fa-var-square-font-awesome-stroke: \\f35c;\n$fa-var-font-awesome-alt: \\f35c;\n$fa-var-atlassian: \\f77b;\n$fa-var-linkedin-in: \\f0e1;\n$fa-var-digital-ocean: \\f391;\n$fa-var-nimblr: \\f5a8;\n$fa-var-chromecast: \\f838;\n$fa-var-evernote: \\f839;\n$fa-var-hacker-news: \\f1d4;\n$fa-var-creative-commons-sampling: \\f4f0;\n$fa-var-adversal: \\f36a;\n$fa-var-creative-commons: \\f25e;\n$fa-var-watchman-monitoring: \\e087;\n$fa-var-fonticons: \\f280;\n$fa-var-weixin: \\f1d7;\n$fa-var-shirtsinbulk: \\f214;\n$fa-var-codepen: \\f1cb;\n$fa-var-git-alt: \\f841;\n$fa-var-lyft: \\f3c3;\n$fa-var-rev: \\f5b2;\n$fa-var-windows: \\f17a;\n$fa-var-wizards-of-the-coast: \\f730;\n$fa-var-square-viadeo: \\f2aa;\n$fa-var-viadeo-square: \\f2aa;\n$fa-var-meetup: \\f2e0;\n$fa-var-centos: \\f789;\n$fa-var-adn: \\f170;\n$fa-var-cloudsmith: \\f384;\n$fa-var-opensuse: \\e62b;\n$fa-var-pied-piper-alt: \\f1a8;\n$fa-var-square-dribbble: \\f397;\n$fa-var-dribbble-square: \\f397;\n$fa-var-codiepie: \\f284;\n$fa-var-node: \\f419;\n$fa-var-mix: \\f3cb;\n$fa-var-steam: \\f1b6;\n$fa-var-cc-apple-pay: \\f416;\n$fa-var-scribd: \\f28a;\n$fa-var-debian: \\e60b;\n$fa-var-openid: \\f19b;\n$fa-var-instalod: \\e081;\n$fa-var-files-pinwheel: \\e69f;\n$fa-var-expeditedssl: \\f23e;\n$fa-var-sellcast: \\f2da;\n$fa-var-square-twitter: \\f081;\n$fa-var-twitter-square: \\f081;\n$fa-var-r-project: \\f4f7;\n$fa-var-delicious: \\f1a5;\n$fa-var-freebsd: \\f3a4;\n$fa-var-vuejs: \\f41f;\n$fa-var-accusoft: \\f369;\n$fa-var-ioxhost: \\f208;\n$fa-var-fonticons-fi: \\f3a2;\n$fa-var-app-store: \\f36f;\n$fa-var-cc-mastercard: \\f1f1;\n$fa-var-itunes-note: \\f3b5;\n$fa-var-golang: \\e40f;\n$fa-var-kickstarter: \\f3bb;\n$fa-var-square-kickstarter: \\f3bb;\n$fa-var-grav: \\f2d6;\n$fa-var-weibo: \\f18a;\n$fa-var-uncharted: \\e084;\n$fa-var-firstdraft: \\f3a1;\n$fa-var-square-youtube: \\f431;\n$fa-var-youtube-square: \\f431;\n$fa-var-wikipedia-w: \\f266;\n$fa-var-wpressr: \\f3e4;\n$fa-var-rendact: \\f3e4;\n$fa-var-angellist: \\f209;\n$fa-var-galactic-republic: \\f50c;\n$fa-var-nfc-directional: \\e530;\n$fa-var-skype: \\f17e;\n$fa-var-joget: \\f3b7;\n$fa-var-fedora: \\f798;\n$fa-var-stripe-s: \\f42a;\n$fa-var-meta: \\e49b;\n$fa-var-laravel: \\f3bd;\n$fa-var-hotjar: \\f3b1;\n$fa-var-bluetooth-b: \\f294;\n$fa-var-square-letterboxd: \\e62e;\n$fa-var-sticker-mule: \\f3f7;\n$fa-var-creative-commons-zero: \\f4f3;\n$fa-var-hips: \\f452;\n$fa-var-css: \\e6a2;\n$fa-var-behance: \\f1b4;\n$fa-var-reddit: \\f1a1;\n$fa-var-discord: \\f392;\n$fa-var-chrome: \\f268;\n$fa-var-app-store-ios: \\f370;\n$fa-var-cc-discover: \\f1f2;\n$fa-var-wpbeginner: \\f297;\n$fa-var-confluence: \\f78d;\n$fa-var-shoelace: \\e60c;\n$fa-var-mdb: \\f8ca;\n$fa-var-dochub: \\f394;\n$fa-var-accessible-icon: \\f368;\n$fa-var-ebay: \\f4f4;\n$fa-var-amazon: \\f270;\n$fa-var-unsplash: \\e07c;\n$fa-var-yarn: \\f7e3;\n$fa-var-square-steam: \\f1b7;\n$fa-var-steam-square: \\f1b7;\n$fa-var-500px: \\f26e;\n$fa-var-square-vimeo: \\f194;\n$fa-var-vimeo-square: \\f194;\n$fa-var-asymmetrik: \\f372;\n$fa-var-font-awesome: \\f2b4;\n$fa-var-font-awesome-flag: \\f2b4;\n$fa-var-font-awesome-logo-full: \\f2b4;\n$fa-var-gratipay: \\f184;\n$fa-var-apple: \\f179;\n$fa-var-hive: \\e07f;\n$fa-var-gitkraken: \\f3a6;\n$fa-var-keybase: \\f4f5;\n$fa-var-apple-pay: \\f415;\n$fa-var-padlet: \\e4a0;\n$fa-var-amazon-pay: \\f42c;\n$fa-var-square-github: \\f092;\n$fa-var-github-square: \\f092;\n$fa-var-stumbleupon: \\f1a4;\n$fa-var-fedex: \\f797;\n$fa-var-phoenix-framework: \\f3dc;\n$fa-var-shopify: \\e057;\n$fa-var-neos: \\f612;\n$fa-var-square-threads: \\e619;\n$fa-var-hackerrank: \\f5f7;\n$fa-var-researchgate: \\f4f8;\n$fa-var-swift: \\f8e1;\n$fa-var-angular: \\f420;\n$fa-var-speakap: \\f3f3;\n$fa-var-angrycreative: \\f36e;\n$fa-var-y-combinator: \\f23b;\n$fa-var-empire: \\f1d1;\n$fa-var-envira: \\f299;\n$fa-var-google-scholar: \\e63b;\n$fa-var-square-gitlab: \\e5ae;\n$fa-var-gitlab-square: \\e5ae;\n$fa-var-studiovinari: \\f3f8;\n$fa-var-pied-piper: \\f2ae;\n$fa-var-wordpress: \\f19a;\n$fa-var-product-hunt: \\f288;\n$fa-var-firefox: \\f269;\n$fa-var-linode: \\f2b8;\n$fa-var-goodreads: \\f3a8;\n$fa-var-square-odnoklassniki: \\f264;\n$fa-var-odnoklassniki-square: \\f264;\n$fa-var-jsfiddle: \\f1cc;\n$fa-var-sith: \\f512;\n$fa-var-themeisle: \\f2b2;\n$fa-var-page4: \\f3d7;\n$fa-var-hashnode: \\e499;\n$fa-var-react: \\f41b;\n$fa-var-cc-paypal: \\f1f4;\n$fa-var-squarespace: \\f5be;\n$fa-var-cc-stripe: \\f1f5;\n$fa-var-creative-commons-share: \\f4f2;\n$fa-var-bitcoin: \\f379;\n$fa-var-keycdn: \\f3ba;\n$fa-var-opera: \\f26a;\n$fa-var-itch-io: \\f83a;\n$fa-var-umbraco: \\f8e8;\n$fa-var-galactic-senate: \\f50d;\n$fa-var-ubuntu: \\f7df;\n$fa-var-draft2digital: \\f396;\n$fa-var-stripe: \\f429;\n$fa-var-houzz: \\f27c;\n$fa-var-gg: \\f260;\n$fa-var-dhl: \\f790;\n$fa-var-square-pinterest: \\f0d3;\n$fa-var-pinterest-square: \\f0d3;\n$fa-var-xing: \\f168;\n$fa-var-blackberry: \\f37b;\n$fa-var-creative-commons-pd: \\f4ec;\n$fa-var-playstation: \\f3df;\n$fa-var-quinscape: \\f459;\n$fa-var-less: \\f41d;\n$fa-var-blogger-b: \\f37d;\n$fa-var-opencart: \\f23d;\n$fa-var-vine: \\f1ca;\n$fa-var-signal-messenger: \\e663;\n$fa-var-paypal: \\f1ed;\n$fa-var-gitlab: \\f296;\n$fa-var-typo3: \\f42b;\n$fa-var-reddit-alien: \\f281;\n$fa-var-yahoo: \\f19e;\n$fa-var-dailymotion: \\e052;\n$fa-var-affiliatetheme: \\f36b;\n$fa-var-pied-piper-pp: \\f1a7;\n$fa-var-bootstrap: \\f836;\n$fa-var-odnoklassniki: \\f263;\n$fa-var-nfc-symbol: \\e531;\n$fa-var-mintbit: \\e62f;\n$fa-var-ethereum: \\f42e;\n$fa-var-speaker-deck: \\f83c;\n$fa-var-creative-commons-nc-eu: \\f4e9;\n$fa-var-patreon: \\f3d9;\n$fa-var-avianex: \\f374;\n$fa-var-ello: \\f5f1;\n$fa-var-gofore: \\f3a7;\n$fa-var-bimobject: \\f378;\n$fa-var-brave-reverse: \\e63d;\n$fa-var-facebook-f: \\f39e;\n$fa-var-square-google-plus: \\f0d4;\n$fa-var-google-plus-square: \\f0d4;\n$fa-var-web-awesome: \\e682;\n$fa-var-mandalorian: \\f50f;\n$fa-var-first-order-alt: \\f50a;\n$fa-var-osi: \\f41a;\n$fa-var-google-wallet: \\f1ee;\n$fa-var-d-and-d-beyond: \\f6ca;\n$fa-var-periscope: \\f3da;\n$fa-var-fulcrum: \\f50b;\n$fa-var-cloudscale: \\f383;\n$fa-var-forumbee: \\f211;\n$fa-var-mizuni: \\f3cc;\n$fa-var-schlix: \\f3ea;\n$fa-var-square-xing: \\f169;\n$fa-var-xing-square: \\f169;\n$fa-var-bandcamp: \\f2d5;\n$fa-var-wpforms: \\f298;\n$fa-var-cloudversify: \\f385;\n$fa-var-usps: \\f7e1;\n$fa-var-megaport: \\f5a3;\n$fa-var-magento: \\f3c4;\n$fa-var-spotify: \\f1bc;\n$fa-var-optin-monster: \\f23c;\n$fa-var-fly: \\f417;\n$fa-var-square-bluesky: \\e6a3;\n$fa-var-aviato: \\f421;\n$fa-var-itunes: \\f3b4;\n$fa-var-cuttlefish: \\f38c;\n$fa-var-blogger: \\f37c;\n$fa-var-flickr: \\f16e;\n$fa-var-viber: \\f409;\n$fa-var-soundcloud: \\f1be;\n$fa-var-digg: \\f1a6;\n$fa-var-tencent-weibo: \\f1d5;\n$fa-var-letterboxd: \\e62d;\n$fa-var-symfony: \\f83d;\n$fa-var-maxcdn: \\f136;\n$fa-var-etsy: \\f2d7;\n$fa-var-facebook-messenger: \\f39f;\n$fa-var-audible: \\f373;\n$fa-var-think-peaks: \\f731;\n$fa-var-bilibili: \\e3d9;\n$fa-var-erlang: \\f39d;\n$fa-var-x-twitter: \\e61b;\n$fa-var-cotton-bureau: \\f89e;\n$fa-var-dashcube: \\f210;\n$fa-var-42-group: \\e080;\n$fa-var-innosoft: \\e080;\n$fa-var-stack-exchange: \\f18d;\n$fa-var-elementor: \\f430;\n$fa-var-square-pied-piper: \\e01e;\n$fa-var-pied-piper-square: \\e01e;\n$fa-var-creative-commons-nd: \\f4eb;\n$fa-var-palfed: \\f3d8;\n$fa-var-superpowers: \\f2dd;\n$fa-var-resolving: \\f3e7;\n$fa-var-xbox: \\f412;\n$fa-var-square-web-awesome-stroke: \\e684;\n$fa-var-searchengin: \\f3eb;\n$fa-var-tiktok: \\e07b;\n$fa-var-square-facebook: \\f082;\n$fa-var-facebook-square: \\f082;\n$fa-var-renren: \\f18b;\n$fa-var-linux: \\f17c;\n$fa-var-glide: \\f2a5;\n$fa-var-linkedin: \\f08c;\n$fa-var-hubspot: \\f3b2;\n$fa-var-deploydog: \\f38e;\n$fa-var-twitch: \\f1e8;\n$fa-var-flutter: \\e694;\n$fa-var-ravelry: \\f2d9;\n$fa-var-mixer: \\e056;\n$fa-var-square-lastfm: \\f203;\n$fa-var-lastfm-square: \\f203;\n$fa-var-vimeo: \\f40a;\n$fa-var-mendeley: \\f7b3;\n$fa-var-uniregistry: \\f404;\n$fa-var-figma: \\f799;\n$fa-var-creative-commons-remix: \\f4ee;\n$fa-var-cc-amazon-pay: \\f42d;\n$fa-var-dropbox: \\f16b;\n$fa-var-instagram: \\f16d;\n$fa-var-cmplid: \\e360;\n$fa-var-upwork: \\e641;\n$fa-var-facebook: \\f09a;\n$fa-var-gripfire: \\f3ac;\n$fa-var-jedi-order: \\f50e;\n$fa-var-uikit: \\f403;\n$fa-var-fort-awesome-alt: \\f3a3;\n$fa-var-phabricator: \\f3db;\n$fa-var-ussunnah: \\f407;\n$fa-var-earlybirds: \\f39a;\n$fa-var-trade-federation: \\f513;\n$fa-var-autoprefixer: \\f41c;\n$fa-var-whatsapp: \\f232;\n$fa-var-square-upwork: \\e67c;\n$fa-var-slideshare: \\f1e7;\n$fa-var-google-play: \\f3ab;\n$fa-var-viadeo: \\f2a9;\n$fa-var-line: \\f3c0;\n$fa-var-google-drive: \\f3aa;\n$fa-var-servicestack: \\f3ec;\n$fa-var-simplybuilt: \\f215;\n$fa-var-bitbucket: \\f171;\n$fa-var-imdb: \\f2d8;\n$fa-var-deezer: \\e077;\n$fa-var-raspberry-pi: \\f7bb;\n$fa-var-jira: \\f7b1;\n$fa-var-docker: \\f395;\n$fa-var-screenpal: \\e570;\n$fa-var-bluetooth: \\f293;\n$fa-var-gitter: \\f426;\n$fa-var-d-and-d: \\f38d;\n$fa-var-microblog: \\e01a;\n$fa-var-cc-diners-club: \\f24c;\n$fa-var-gg-circle: \\f261;\n$fa-var-pied-piper-hat: \\f4e5;\n$fa-var-kickstarter-k: \\f3bc;\n$fa-var-yandex: \\f413;\n$fa-var-readme: \\f4d5;\n$fa-var-html5: \\f13b;\n$fa-var-sellsy: \\f213;\n$fa-var-square-web-awesome: \\e683;\n$fa-var-sass: \\f41e;\n$fa-var-wirsindhandwerk: \\e2d0;\n$fa-var-wsh: \\e2d0;\n$fa-var-buromobelexperte: \\f37f;\n$fa-var-salesforce: \\f83b;\n$fa-var-octopus-deploy: \\e082;\n$fa-var-medapps: \\f3c6;\n$fa-var-ns8: \\f3d5;\n$fa-var-pinterest-p: \\f231;\n$fa-var-apper: \\f371;\n$fa-var-fort-awesome: \\f286;\n$fa-var-waze: \\f83f;\n$fa-var-bluesky: \\e671;\n$fa-var-cc-jcb: \\f24b;\n$fa-var-snapchat: \\f2ab;\n$fa-var-snapchat-ghost: \\f2ab;\n$fa-var-fantasy-flight-games: \\f6dc;\n$fa-var-rust: \\e07a;\n$fa-var-wix: \\f5cf;\n$fa-var-square-behance: \\f1b5;\n$fa-var-behance-square: \\f1b5;\n$fa-var-supple: \\f3f9;\n$fa-var-webflow: \\e65c;\n$fa-var-rebel: \\f1d0;\n$fa-var-css3: \\f13c;\n$fa-var-staylinked: \\f3f5;\n$fa-var-kaggle: \\f5fa;\n$fa-var-space-awesome: \\e5ac;\n$fa-var-deviantart: \\f1bd;\n$fa-var-cpanel: \\f388;\n$fa-var-goodreads-g: \\f3a9;\n$fa-var-square-git: \\f1d2;\n$fa-var-git-square: \\f1d2;\n$fa-var-square-tumblr: \\f174;\n$fa-var-tumblr-square: \\f174;\n$fa-var-trello: \\f181;\n$fa-var-creative-commons-nc-jp: \\f4ea;\n$fa-var-get-pocket: \\f265;\n$fa-var-perbyte: \\e083;\n$fa-var-grunt: \\f3ad;\n$fa-var-weebly: \\f5cc;\n$fa-var-connectdevelop: \\f20e;\n$fa-var-leanpub: \\f212;\n$fa-var-black-tie: \\f27e;\n$fa-var-themeco: \\f5c6;\n$fa-var-python: \\f3e2;\n$fa-var-android: \\f17b;\n$fa-var-bots: \\e340;\n$fa-var-free-code-camp: \\f2c5;\n$fa-var-hornbill: \\f592;\n$fa-var-js: \\f3b8;\n$fa-var-ideal: \\e013;\n$fa-var-git: \\f1d3;\n$fa-var-dev: \\f6cc;\n$fa-var-sketch: \\f7c6;\n$fa-var-yandex-international: \\f414;\n$fa-var-cc-amex: \\f1f3;\n$fa-var-uber: \\f402;\n$fa-var-github: \\f09b;\n$fa-var-php: \\f457;\n$fa-var-alipay: \\f642;\n$fa-var-youtube: \\f167;\n$fa-var-skyatlas: \\f216;\n$fa-var-firefox-browser: \\e007;\n$fa-var-replyd: \\f3e6;\n$fa-var-suse: \\f7d6;\n$fa-var-jenkins: \\f3b6;\n$fa-var-twitter: \\f099;\n$fa-var-rockrms: \\f3e9;\n$fa-var-pinterest: \\f0d2;\n$fa-var-buffer: \\f837;\n$fa-var-npm: \\f3d4;\n$fa-var-yammer: \\f840;\n$fa-var-btc: \\f15a;\n$fa-var-dribbble: \\f17d;\n$fa-var-stumbleupon-circle: \\f1a3;\n$fa-var-internet-explorer: \\f26b;\n$fa-var-stubber: \\e5c7;\n$fa-var-telegram: \\f2c6;\n$fa-var-telegram-plane: \\f2c6;\n$fa-var-old-republic: \\f510;\n$fa-var-odysee: \\e5c6;\n$fa-var-square-whatsapp: \\f40c;\n$fa-var-whatsapp-square: \\f40c;\n$fa-var-node-js: \\f3d3;\n$fa-var-edge-legacy: \\e078;\n$fa-var-slack: \\f198;\n$fa-var-slack-hash: \\f198;\n$fa-var-medrt: \\f3c8;\n$fa-var-usb: \\f287;\n$fa-var-tumblr: \\f173;\n$fa-var-vaadin: \\f408;\n$fa-var-quora: \\f2c4;\n$fa-var-square-x-twitter: \\e61a;\n$fa-var-reacteurope: \\f75d;\n$fa-var-medium: \\f23a;\n$fa-var-medium-m: \\f23a;\n$fa-var-amilia: \\f36d;\n$fa-var-mixcloud: \\f289;\n$fa-var-flipboard: \\f44d;\n$fa-var-viacoin: \\f237;\n$fa-var-critical-role: \\f6c9;\n$fa-var-sitrox: \\e44a;\n$fa-var-discourse: \\f393;\n$fa-var-joomla: \\f1aa;\n$fa-var-mastodon: \\f4f6;\n$fa-var-airbnb: \\f834;\n$fa-var-wolf-pack-battalion: \\f514;\n$fa-var-buy-n-large: \\f8a6;\n$fa-var-gulp: \\f3ae;\n$fa-var-creative-commons-sampling-plus: \\f4f1;\n$fa-var-strava: \\f428;\n$fa-var-ember: \\f423;\n$fa-var-canadian-maple-leaf: \\f785;\n$fa-var-teamspeak: \\f4f9;\n$fa-var-pushed: \\f3e1;\n$fa-var-wordpress-simple: \\f411;\n$fa-var-nutritionix: \\f3d6;\n$fa-var-wodu: \\e088;\n$fa-var-google-pay: \\e079;\n$fa-var-intercom: \\f7af;\n$fa-var-zhihu: \\f63f;\n$fa-var-korvue: \\f42f;\n$fa-var-pix: \\e43a;\n$fa-var-steam-symbol: \\f3f6;\n\n$fa-icons: (\n \"0\": $fa-var-0,\n \"1\": $fa-var-1,\n \"2\": $fa-var-2,\n \"3\": $fa-var-3,\n \"4\": $fa-var-4,\n \"5\": $fa-var-5,\n \"6\": $fa-var-6,\n \"7\": $fa-var-7,\n \"8\": $fa-var-8,\n \"9\": $fa-var-9,\n \"fill-drip\": $fa-var-fill-drip,\n \"arrows-to-circle\": $fa-var-arrows-to-circle,\n \"circle-chevron-right\": $fa-var-circle-chevron-right,\n \"chevron-circle-right\": $fa-var-chevron-circle-right,\n \"at\": $fa-var-at,\n \"trash-can\": $fa-var-trash-can,\n \"trash-alt\": $fa-var-trash-alt,\n \"text-height\": $fa-var-text-height,\n \"user-xmark\": $fa-var-user-xmark,\n \"user-times\": $fa-var-user-times,\n \"stethoscope\": $fa-var-stethoscope,\n \"message\": $fa-var-message,\n \"comment-alt\": $fa-var-comment-alt,\n \"info\": $fa-var-info,\n \"down-left-and-up-right-to-center\": $fa-var-down-left-and-up-right-to-center,\n \"compress-alt\": $fa-var-compress-alt,\n \"explosion\": $fa-var-explosion,\n \"file-lines\": $fa-var-file-lines,\n \"file-alt\": $fa-var-file-alt,\n \"file-text\": $fa-var-file-text,\n \"wave-square\": $fa-var-wave-square,\n \"ring\": $fa-var-ring,\n \"building-un\": $fa-var-building-un,\n \"dice-three\": $fa-var-dice-three,\n \"calendar-days\": $fa-var-calendar-days,\n \"calendar-alt\": $fa-var-calendar-alt,\n \"anchor-circle-check\": $fa-var-anchor-circle-check,\n \"building-circle-arrow-right\": $fa-var-building-circle-arrow-right,\n \"volleyball\": $fa-var-volleyball,\n \"volleyball-ball\": $fa-var-volleyball-ball,\n \"arrows-up-to-line\": $fa-var-arrows-up-to-line,\n \"sort-down\": $fa-var-sort-down,\n \"sort-desc\": $fa-var-sort-desc,\n \"circle-minus\": $fa-var-circle-minus,\n \"minus-circle\": $fa-var-minus-circle,\n \"door-open\": $fa-var-door-open,\n \"right-from-bracket\": $fa-var-right-from-bracket,\n \"sign-out-alt\": $fa-var-sign-out-alt,\n \"atom\": $fa-var-atom,\n \"soap\": $fa-var-soap,\n \"icons\": $fa-var-icons,\n \"heart-music-camera-bolt\": $fa-var-heart-music-camera-bolt,\n \"microphone-lines-slash\": $fa-var-microphone-lines-slash,\n \"microphone-alt-slash\": $fa-var-microphone-alt-slash,\n \"bridge-circle-check\": $fa-var-bridge-circle-check,\n \"pump-medical\": $fa-var-pump-medical,\n \"fingerprint\": $fa-var-fingerprint,\n \"hand-point-right\": $fa-var-hand-point-right,\n \"magnifying-glass-location\": $fa-var-magnifying-glass-location,\n \"search-location\": $fa-var-search-location,\n \"forward-step\": $fa-var-forward-step,\n \"step-forward\": $fa-var-step-forward,\n \"face-smile-beam\": $fa-var-face-smile-beam,\n \"smile-beam\": $fa-var-smile-beam,\n \"flag-checkered\": $fa-var-flag-checkered,\n \"football\": $fa-var-football,\n \"football-ball\": $fa-var-football-ball,\n \"school-circle-exclamation\": $fa-var-school-circle-exclamation,\n \"crop\": $fa-var-crop,\n \"angles-down\": $fa-var-angles-down,\n \"angle-double-down\": $fa-var-angle-double-down,\n \"users-rectangle\": $fa-var-users-rectangle,\n \"people-roof\": $fa-var-people-roof,\n \"people-line\": $fa-var-people-line,\n \"beer-mug-empty\": $fa-var-beer-mug-empty,\n \"beer\": $fa-var-beer,\n \"diagram-predecessor\": $fa-var-diagram-predecessor,\n \"arrow-up-long\": $fa-var-arrow-up-long,\n \"long-arrow-up\": $fa-var-long-arrow-up,\n \"fire-flame-simple\": $fa-var-fire-flame-simple,\n \"burn\": $fa-var-burn,\n \"person\": $fa-var-person,\n \"male\": $fa-var-male,\n \"laptop\": $fa-var-laptop,\n \"file-csv\": $fa-var-file-csv,\n \"menorah\": $fa-var-menorah,\n \"truck-plane\": $fa-var-truck-plane,\n \"record-vinyl\": $fa-var-record-vinyl,\n \"face-grin-stars\": $fa-var-face-grin-stars,\n \"grin-stars\": $fa-var-grin-stars,\n \"bong\": $fa-var-bong,\n \"spaghetti-monster-flying\": $fa-var-spaghetti-monster-flying,\n \"pastafarianism\": $fa-var-pastafarianism,\n \"arrow-down-up-across-line\": $fa-var-arrow-down-up-across-line,\n \"spoon\": $fa-var-spoon,\n \"utensil-spoon\": $fa-var-utensil-spoon,\n \"jar-wheat\": $fa-var-jar-wheat,\n \"envelopes-bulk\": $fa-var-envelopes-bulk,\n \"mail-bulk\": $fa-var-mail-bulk,\n \"file-circle-exclamation\": $fa-var-file-circle-exclamation,\n \"circle-h\": $fa-var-circle-h,\n \"hospital-symbol\": $fa-var-hospital-symbol,\n \"pager\": $fa-var-pager,\n \"address-book\": $fa-var-address-book,\n \"contact-book\": $fa-var-contact-book,\n \"strikethrough\": $fa-var-strikethrough,\n \"k\": $fa-var-k,\n \"landmark-flag\": $fa-var-landmark-flag,\n \"pencil\": $fa-var-pencil,\n \"pencil-alt\": $fa-var-pencil-alt,\n \"backward\": $fa-var-backward,\n \"caret-right\": $fa-var-caret-right,\n \"comments\": $fa-var-comments,\n \"paste\": $fa-var-paste,\n \"file-clipboard\": $fa-var-file-clipboard,\n \"code-pull-request\": $fa-var-code-pull-request,\n \"clipboard-list\": $fa-var-clipboard-list,\n \"truck-ramp-box\": $fa-var-truck-ramp-box,\n \"truck-loading\": $fa-var-truck-loading,\n \"user-check\": $fa-var-user-check,\n \"vial-virus\": $fa-var-vial-virus,\n \"sheet-plastic\": $fa-var-sheet-plastic,\n \"blog\": $fa-var-blog,\n \"user-ninja\": $fa-var-user-ninja,\n \"person-arrow-up-from-line\": $fa-var-person-arrow-up-from-line,\n \"scroll-torah\": $fa-var-scroll-torah,\n \"torah\": $fa-var-torah,\n \"broom-ball\": $fa-var-broom-ball,\n \"quidditch\": $fa-var-quidditch,\n \"quidditch-broom-ball\": $fa-var-quidditch-broom-ball,\n \"toggle-off\": $fa-var-toggle-off,\n \"box-archive\": $fa-var-box-archive,\n \"archive\": $fa-var-archive,\n \"person-drowning\": $fa-var-person-drowning,\n \"arrow-down-9-1\": $fa-var-arrow-down-9-1,\n \"sort-numeric-desc\": $fa-var-sort-numeric-desc,\n \"sort-numeric-down-alt\": $fa-var-sort-numeric-down-alt,\n \"face-grin-tongue-squint\": $fa-var-face-grin-tongue-squint,\n \"grin-tongue-squint\": $fa-var-grin-tongue-squint,\n \"spray-can\": $fa-var-spray-can,\n \"truck-monster\": $fa-var-truck-monster,\n \"w\": $fa-var-w,\n \"earth-africa\": $fa-var-earth-africa,\n \"globe-africa\": $fa-var-globe-africa,\n \"rainbow\": $fa-var-rainbow,\n \"circle-notch\": $fa-var-circle-notch,\n \"tablet-screen-button\": $fa-var-tablet-screen-button,\n \"tablet-alt\": $fa-var-tablet-alt,\n \"paw\": $fa-var-paw,\n \"cloud\": $fa-var-cloud,\n \"trowel-bricks\": $fa-var-trowel-bricks,\n \"face-flushed\": $fa-var-face-flushed,\n \"flushed\": $fa-var-flushed,\n \"hospital-user\": $fa-var-hospital-user,\n \"tent-arrow-left-right\": $fa-var-tent-arrow-left-right,\n \"gavel\": $fa-var-gavel,\n \"legal\": $fa-var-legal,\n \"binoculars\": $fa-var-binoculars,\n \"microphone-slash\": $fa-var-microphone-slash,\n \"box-tissue\": $fa-var-box-tissue,\n \"motorcycle\": $fa-var-motorcycle,\n \"bell-concierge\": $fa-var-bell-concierge,\n \"concierge-bell\": $fa-var-concierge-bell,\n \"pen-ruler\": $fa-var-pen-ruler,\n \"pencil-ruler\": $fa-var-pencil-ruler,\n \"people-arrows\": $fa-var-people-arrows,\n \"people-arrows-left-right\": $fa-var-people-arrows-left-right,\n \"mars-and-venus-burst\": $fa-var-mars-and-venus-burst,\n \"square-caret-right\": $fa-var-square-caret-right,\n \"caret-square-right\": $fa-var-caret-square-right,\n \"scissors\": $fa-var-scissors,\n \"cut\": $fa-var-cut,\n \"sun-plant-wilt\": $fa-var-sun-plant-wilt,\n \"toilets-portable\": $fa-var-toilets-portable,\n \"hockey-puck\": $fa-var-hockey-puck,\n \"table\": $fa-var-table,\n \"magnifying-glass-arrow-right\": $fa-var-magnifying-glass-arrow-right,\n \"tachograph-digital\": $fa-var-tachograph-digital,\n \"digital-tachograph\": $fa-var-digital-tachograph,\n \"users-slash\": $fa-var-users-slash,\n \"clover\": $fa-var-clover,\n \"reply\": $fa-var-reply,\n \"mail-reply\": $fa-var-mail-reply,\n \"star-and-crescent\": $fa-var-star-and-crescent,\n \"house-fire\": $fa-var-house-fire,\n \"square-minus\": $fa-var-square-minus,\n \"minus-square\": $fa-var-minus-square,\n \"helicopter\": $fa-var-helicopter,\n \"compass\": $fa-var-compass,\n \"square-caret-down\": $fa-var-square-caret-down,\n \"caret-square-down\": $fa-var-caret-square-down,\n \"file-circle-question\": $fa-var-file-circle-question,\n \"laptop-code\": $fa-var-laptop-code,\n \"swatchbook\": $fa-var-swatchbook,\n \"prescription-bottle\": $fa-var-prescription-bottle,\n \"bars\": $fa-var-bars,\n \"navicon\": $fa-var-navicon,\n \"people-group\": $fa-var-people-group,\n \"hourglass-end\": $fa-var-hourglass-end,\n \"hourglass-3\": $fa-var-hourglass-3,\n \"heart-crack\": $fa-var-heart-crack,\n \"heart-broken\": $fa-var-heart-broken,\n \"square-up-right\": $fa-var-square-up-right,\n \"external-link-square-alt\": $fa-var-external-link-square-alt,\n \"face-kiss-beam\": $fa-var-face-kiss-beam,\n \"kiss-beam\": $fa-var-kiss-beam,\n \"film\": $fa-var-film,\n \"ruler-horizontal\": $fa-var-ruler-horizontal,\n \"people-robbery\": $fa-var-people-robbery,\n \"lightbulb\": $fa-var-lightbulb,\n \"caret-left\": $fa-var-caret-left,\n \"circle-exclamation\": $fa-var-circle-exclamation,\n \"exclamation-circle\": $fa-var-exclamation-circle,\n \"school-circle-xmark\": $fa-var-school-circle-xmark,\n \"arrow-right-from-bracket\": $fa-var-arrow-right-from-bracket,\n \"sign-out\": $fa-var-sign-out,\n \"circle-chevron-down\": $fa-var-circle-chevron-down,\n \"chevron-circle-down\": $fa-var-chevron-circle-down,\n \"unlock-keyhole\": $fa-var-unlock-keyhole,\n \"unlock-alt\": $fa-var-unlock-alt,\n \"cloud-showers-heavy\": $fa-var-cloud-showers-heavy,\n \"headphones-simple\": $fa-var-headphones-simple,\n \"headphones-alt\": $fa-var-headphones-alt,\n \"sitemap\": $fa-var-sitemap,\n \"circle-dollar-to-slot\": $fa-var-circle-dollar-to-slot,\n \"donate\": $fa-var-donate,\n \"memory\": $fa-var-memory,\n \"road-spikes\": $fa-var-road-spikes,\n \"fire-burner\": $fa-var-fire-burner,\n \"flag\": $fa-var-flag,\n \"hanukiah\": $fa-var-hanukiah,\n \"feather\": $fa-var-feather,\n \"volume-low\": $fa-var-volume-low,\n \"volume-down\": $fa-var-volume-down,\n \"comment-slash\": $fa-var-comment-slash,\n \"cloud-sun-rain\": $fa-var-cloud-sun-rain,\n \"compress\": $fa-var-compress,\n \"wheat-awn\": $fa-var-wheat-awn,\n \"wheat-alt\": $fa-var-wheat-alt,\n \"ankh\": $fa-var-ankh,\n \"hands-holding-child\": $fa-var-hands-holding-child,\n \"asterisk\": $fa-var-asterisk,\n \"square-check\": $fa-var-square-check,\n \"check-square\": $fa-var-check-square,\n \"peseta-sign\": $fa-var-peseta-sign,\n \"heading\": $fa-var-heading,\n \"header\": $fa-var-header,\n \"ghost\": $fa-var-ghost,\n \"list\": $fa-var-list,\n \"list-squares\": $fa-var-list-squares,\n \"square-phone-flip\": $fa-var-square-phone-flip,\n \"phone-square-alt\": $fa-var-phone-square-alt,\n \"cart-plus\": $fa-var-cart-plus,\n \"gamepad\": $fa-var-gamepad,\n \"circle-dot\": $fa-var-circle-dot,\n \"dot-circle\": $fa-var-dot-circle,\n \"face-dizzy\": $fa-var-face-dizzy,\n \"dizzy\": $fa-var-dizzy,\n \"egg\": $fa-var-egg,\n \"house-medical-circle-xmark\": $fa-var-house-medical-circle-xmark,\n \"campground\": $fa-var-campground,\n \"folder-plus\": $fa-var-folder-plus,\n \"futbol\": $fa-var-futbol,\n \"futbol-ball\": $fa-var-futbol-ball,\n \"soccer-ball\": $fa-var-soccer-ball,\n \"paintbrush\": $fa-var-paintbrush,\n \"paint-brush\": $fa-var-paint-brush,\n \"lock\": $fa-var-lock,\n \"gas-pump\": $fa-var-gas-pump,\n \"hot-tub-person\": $fa-var-hot-tub-person,\n \"hot-tub\": $fa-var-hot-tub,\n \"map-location\": $fa-var-map-location,\n \"map-marked\": $fa-var-map-marked,\n \"house-flood-water\": $fa-var-house-flood-water,\n \"tree\": $fa-var-tree,\n \"bridge-lock\": $fa-var-bridge-lock,\n \"sack-dollar\": $fa-var-sack-dollar,\n \"pen-to-square\": $fa-var-pen-to-square,\n \"edit\": $fa-var-edit,\n \"car-side\": $fa-var-car-side,\n \"share-nodes\": $fa-var-share-nodes,\n \"share-alt\": $fa-var-share-alt,\n \"heart-circle-minus\": $fa-var-heart-circle-minus,\n \"hourglass-half\": $fa-var-hourglass-half,\n \"hourglass-2\": $fa-var-hourglass-2,\n \"microscope\": $fa-var-microscope,\n \"sink\": $fa-var-sink,\n \"bag-shopping\": $fa-var-bag-shopping,\n \"shopping-bag\": $fa-var-shopping-bag,\n \"arrow-down-z-a\": $fa-var-arrow-down-z-a,\n \"sort-alpha-desc\": $fa-var-sort-alpha-desc,\n \"sort-alpha-down-alt\": $fa-var-sort-alpha-down-alt,\n \"mitten\": $fa-var-mitten,\n \"person-rays\": $fa-var-person-rays,\n \"users\": $fa-var-users,\n \"eye-slash\": $fa-var-eye-slash,\n \"flask-vial\": $fa-var-flask-vial,\n \"hand\": $fa-var-hand,\n \"hand-paper\": $fa-var-hand-paper,\n \"om\": $fa-var-om,\n \"worm\": $fa-var-worm,\n \"house-circle-xmark\": $fa-var-house-circle-xmark,\n \"plug\": $fa-var-plug,\n \"chevron-up\": $fa-var-chevron-up,\n \"hand-spock\": $fa-var-hand-spock,\n \"stopwatch\": $fa-var-stopwatch,\n \"face-kiss\": $fa-var-face-kiss,\n \"kiss\": $fa-var-kiss,\n \"bridge-circle-xmark\": $fa-var-bridge-circle-xmark,\n \"face-grin-tongue\": $fa-var-face-grin-tongue,\n \"grin-tongue\": $fa-var-grin-tongue,\n \"chess-bishop\": $fa-var-chess-bishop,\n \"face-grin-wink\": $fa-var-face-grin-wink,\n \"grin-wink\": $fa-var-grin-wink,\n \"ear-deaf\": $fa-var-ear-deaf,\n \"deaf\": $fa-var-deaf,\n \"deafness\": $fa-var-deafness,\n \"hard-of-hearing\": $fa-var-hard-of-hearing,\n \"road-circle-check\": $fa-var-road-circle-check,\n \"dice-five\": $fa-var-dice-five,\n \"square-rss\": $fa-var-square-rss,\n \"rss-square\": $fa-var-rss-square,\n \"land-mine-on\": $fa-var-land-mine-on,\n \"i-cursor\": $fa-var-i-cursor,\n \"stamp\": $fa-var-stamp,\n \"stairs\": $fa-var-stairs,\n \"i\": $fa-var-i,\n \"hryvnia-sign\": $fa-var-hryvnia-sign,\n \"hryvnia\": $fa-var-hryvnia,\n \"pills\": $fa-var-pills,\n \"face-grin-wide\": $fa-var-face-grin-wide,\n \"grin-alt\": $fa-var-grin-alt,\n \"tooth\": $fa-var-tooth,\n \"v\": $fa-var-v,\n \"bangladeshi-taka-sign\": $fa-var-bangladeshi-taka-sign,\n \"bicycle\": $fa-var-bicycle,\n \"staff-snake\": $fa-var-staff-snake,\n \"rod-asclepius\": $fa-var-rod-asclepius,\n \"rod-snake\": $fa-var-rod-snake,\n \"staff-aesculapius\": $fa-var-staff-aesculapius,\n \"head-side-cough-slash\": $fa-var-head-side-cough-slash,\n \"truck-medical\": $fa-var-truck-medical,\n \"ambulance\": $fa-var-ambulance,\n \"wheat-awn-circle-exclamation\": $fa-var-wheat-awn-circle-exclamation,\n \"snowman\": $fa-var-snowman,\n \"mortar-pestle\": $fa-var-mortar-pestle,\n \"road-barrier\": $fa-var-road-barrier,\n \"school\": $fa-var-school,\n \"igloo\": $fa-var-igloo,\n \"joint\": $fa-var-joint,\n \"angle-right\": $fa-var-angle-right,\n \"horse\": $fa-var-horse,\n \"q\": $fa-var-q,\n \"g\": $fa-var-g,\n \"notes-medical\": $fa-var-notes-medical,\n \"temperature-half\": $fa-var-temperature-half,\n \"temperature-2\": $fa-var-temperature-2,\n \"thermometer-2\": $fa-var-thermometer-2,\n \"thermometer-half\": $fa-var-thermometer-half,\n \"dong-sign\": $fa-var-dong-sign,\n \"capsules\": $fa-var-capsules,\n \"poo-storm\": $fa-var-poo-storm,\n \"poo-bolt\": $fa-var-poo-bolt,\n \"face-frown-open\": $fa-var-face-frown-open,\n \"frown-open\": $fa-var-frown-open,\n \"hand-point-up\": $fa-var-hand-point-up,\n \"money-bill\": $fa-var-money-bill,\n \"bookmark\": $fa-var-bookmark,\n \"align-justify\": $fa-var-align-justify,\n \"umbrella-beach\": $fa-var-umbrella-beach,\n \"helmet-un\": $fa-var-helmet-un,\n \"bullseye\": $fa-var-bullseye,\n \"bacon\": $fa-var-bacon,\n \"hand-point-down\": $fa-var-hand-point-down,\n \"arrow-up-from-bracket\": $fa-var-arrow-up-from-bracket,\n \"folder\": $fa-var-folder,\n \"folder-blank\": $fa-var-folder-blank,\n \"file-waveform\": $fa-var-file-waveform,\n \"file-medical-alt\": $fa-var-file-medical-alt,\n \"radiation\": $fa-var-radiation,\n \"chart-simple\": $fa-var-chart-simple,\n \"mars-stroke\": $fa-var-mars-stroke,\n \"vial\": $fa-var-vial,\n \"gauge\": $fa-var-gauge,\n \"dashboard\": $fa-var-dashboard,\n \"gauge-med\": $fa-var-gauge-med,\n \"tachometer-alt-average\": $fa-var-tachometer-alt-average,\n \"wand-magic-sparkles\": $fa-var-wand-magic-sparkles,\n \"magic-wand-sparkles\": $fa-var-magic-wand-sparkles,\n \"e\": $fa-var-e,\n \"pen-clip\": $fa-var-pen-clip,\n \"pen-alt\": $fa-var-pen-alt,\n \"bridge-circle-exclamation\": $fa-var-bridge-circle-exclamation,\n \"user\": $fa-var-user,\n \"school-circle-check\": $fa-var-school-circle-check,\n \"dumpster\": $fa-var-dumpster,\n \"van-shuttle\": $fa-var-van-shuttle,\n \"shuttle-van\": $fa-var-shuttle-van,\n \"building-user\": $fa-var-building-user,\n \"square-caret-left\": $fa-var-square-caret-left,\n \"caret-square-left\": $fa-var-caret-square-left,\n \"highlighter\": $fa-var-highlighter,\n \"key\": $fa-var-key,\n \"bullhorn\": $fa-var-bullhorn,\n \"globe\": $fa-var-globe,\n \"synagogue\": $fa-var-synagogue,\n \"person-half-dress\": $fa-var-person-half-dress,\n \"road-bridge\": $fa-var-road-bridge,\n \"location-arrow\": $fa-var-location-arrow,\n \"c\": $fa-var-c,\n \"tablet-button\": $fa-var-tablet-button,\n \"building-lock\": $fa-var-building-lock,\n \"pizza-slice\": $fa-var-pizza-slice,\n \"money-bill-wave\": $fa-var-money-bill-wave,\n \"chart-area\": $fa-var-chart-area,\n \"area-chart\": $fa-var-area-chart,\n \"house-flag\": $fa-var-house-flag,\n \"person-circle-minus\": $fa-var-person-circle-minus,\n \"ban\": $fa-var-ban,\n \"cancel\": $fa-var-cancel,\n \"camera-rotate\": $fa-var-camera-rotate,\n \"spray-can-sparkles\": $fa-var-spray-can-sparkles,\n \"air-freshener\": $fa-var-air-freshener,\n \"star\": $fa-var-star,\n \"repeat\": $fa-var-repeat,\n \"cross\": $fa-var-cross,\n \"box\": $fa-var-box,\n \"venus-mars\": $fa-var-venus-mars,\n \"arrow-pointer\": $fa-var-arrow-pointer,\n \"mouse-pointer\": $fa-var-mouse-pointer,\n \"maximize\": $fa-var-maximize,\n \"expand-arrows-alt\": $fa-var-expand-arrows-alt,\n \"charging-station\": $fa-var-charging-station,\n \"shapes\": $fa-var-shapes,\n \"triangle-circle-square\": $fa-var-triangle-circle-square,\n \"shuffle\": $fa-var-shuffle,\n \"random\": $fa-var-random,\n \"person-running\": $fa-var-person-running,\n \"running\": $fa-var-running,\n \"mobile-retro\": $fa-var-mobile-retro,\n \"grip-lines-vertical\": $fa-var-grip-lines-vertical,\n \"spider\": $fa-var-spider,\n \"hands-bound\": $fa-var-hands-bound,\n \"file-invoice-dollar\": $fa-var-file-invoice-dollar,\n \"plane-circle-exclamation\": $fa-var-plane-circle-exclamation,\n \"x-ray\": $fa-var-x-ray,\n \"spell-check\": $fa-var-spell-check,\n \"slash\": $fa-var-slash,\n \"computer-mouse\": $fa-var-computer-mouse,\n \"mouse\": $fa-var-mouse,\n \"arrow-right-to-bracket\": $fa-var-arrow-right-to-bracket,\n \"sign-in\": $fa-var-sign-in,\n \"shop-slash\": $fa-var-shop-slash,\n \"store-alt-slash\": $fa-var-store-alt-slash,\n \"server\": $fa-var-server,\n \"virus-covid-slash\": $fa-var-virus-covid-slash,\n \"shop-lock\": $fa-var-shop-lock,\n \"hourglass-start\": $fa-var-hourglass-start,\n \"hourglass-1\": $fa-var-hourglass-1,\n \"blender-phone\": $fa-var-blender-phone,\n \"building-wheat\": $fa-var-building-wheat,\n \"person-breastfeeding\": $fa-var-person-breastfeeding,\n \"right-to-bracket\": $fa-var-right-to-bracket,\n \"sign-in-alt\": $fa-var-sign-in-alt,\n \"venus\": $fa-var-venus,\n \"passport\": $fa-var-passport,\n \"thumbtack-slash\": $fa-var-thumbtack-slash,\n \"thumb-tack-slash\": $fa-var-thumb-tack-slash,\n \"heart-pulse\": $fa-var-heart-pulse,\n \"heartbeat\": $fa-var-heartbeat,\n \"people-carry-box\": $fa-var-people-carry-box,\n \"people-carry\": $fa-var-people-carry,\n \"temperature-high\": $fa-var-temperature-high,\n \"microchip\": $fa-var-microchip,\n \"crown\": $fa-var-crown,\n \"weight-hanging\": $fa-var-weight-hanging,\n \"xmarks-lines\": $fa-var-xmarks-lines,\n \"file-prescription\": $fa-var-file-prescription,\n \"weight-scale\": $fa-var-weight-scale,\n \"weight\": $fa-var-weight,\n \"user-group\": $fa-var-user-group,\n \"user-friends\": $fa-var-user-friends,\n \"arrow-up-a-z\": $fa-var-arrow-up-a-z,\n \"sort-alpha-up\": $fa-var-sort-alpha-up,\n \"chess-knight\": $fa-var-chess-knight,\n \"face-laugh-squint\": $fa-var-face-laugh-squint,\n \"laugh-squint\": $fa-var-laugh-squint,\n \"wheelchair\": $fa-var-wheelchair,\n \"circle-arrow-up\": $fa-var-circle-arrow-up,\n \"arrow-circle-up\": $fa-var-arrow-circle-up,\n \"toggle-on\": $fa-var-toggle-on,\n \"person-walking\": $fa-var-person-walking,\n \"walking\": $fa-var-walking,\n \"l\": $fa-var-l,\n \"fire\": $fa-var-fire,\n \"bed-pulse\": $fa-var-bed-pulse,\n \"procedures\": $fa-var-procedures,\n \"shuttle-space\": $fa-var-shuttle-space,\n \"space-shuttle\": $fa-var-space-shuttle,\n \"face-laugh\": $fa-var-face-laugh,\n \"laugh\": $fa-var-laugh,\n \"folder-open\": $fa-var-folder-open,\n \"heart-circle-plus\": $fa-var-heart-circle-plus,\n \"code-fork\": $fa-var-code-fork,\n \"city\": $fa-var-city,\n \"microphone-lines\": $fa-var-microphone-lines,\n \"microphone-alt\": $fa-var-microphone-alt,\n \"pepper-hot\": $fa-var-pepper-hot,\n \"unlock\": $fa-var-unlock,\n \"colon-sign\": $fa-var-colon-sign,\n \"headset\": $fa-var-headset,\n \"store-slash\": $fa-var-store-slash,\n \"road-circle-xmark\": $fa-var-road-circle-xmark,\n \"user-minus\": $fa-var-user-minus,\n \"mars-stroke-up\": $fa-var-mars-stroke-up,\n \"mars-stroke-v\": $fa-var-mars-stroke-v,\n \"champagne-glasses\": $fa-var-champagne-glasses,\n \"glass-cheers\": $fa-var-glass-cheers,\n \"clipboard\": $fa-var-clipboard,\n \"house-circle-exclamation\": $fa-var-house-circle-exclamation,\n \"file-arrow-up\": $fa-var-file-arrow-up,\n \"file-upload\": $fa-var-file-upload,\n \"wifi\": $fa-var-wifi,\n \"wifi-3\": $fa-var-wifi-3,\n \"wifi-strong\": $fa-var-wifi-strong,\n \"bath\": $fa-var-bath,\n \"bathtub\": $fa-var-bathtub,\n \"underline\": $fa-var-underline,\n \"user-pen\": $fa-var-user-pen,\n \"user-edit\": $fa-var-user-edit,\n \"signature\": $fa-var-signature,\n \"stroopwafel\": $fa-var-stroopwafel,\n \"bold\": $fa-var-bold,\n \"anchor-lock\": $fa-var-anchor-lock,\n \"building-ngo\": $fa-var-building-ngo,\n \"manat-sign\": $fa-var-manat-sign,\n \"not-equal\": $fa-var-not-equal,\n \"border-top-left\": $fa-var-border-top-left,\n \"border-style\": $fa-var-border-style,\n \"map-location-dot\": $fa-var-map-location-dot,\n \"map-marked-alt\": $fa-var-map-marked-alt,\n \"jedi\": $fa-var-jedi,\n \"square-poll-vertical\": $fa-var-square-poll-vertical,\n \"poll\": $fa-var-poll,\n \"mug-hot\": $fa-var-mug-hot,\n \"car-battery\": $fa-var-car-battery,\n \"battery-car\": $fa-var-battery-car,\n \"gift\": $fa-var-gift,\n \"dice-two\": $fa-var-dice-two,\n \"chess-queen\": $fa-var-chess-queen,\n \"glasses\": $fa-var-glasses,\n \"chess-board\": $fa-var-chess-board,\n \"building-circle-check\": $fa-var-building-circle-check,\n \"person-chalkboard\": $fa-var-person-chalkboard,\n \"mars-stroke-right\": $fa-var-mars-stroke-right,\n \"mars-stroke-h\": $fa-var-mars-stroke-h,\n \"hand-back-fist\": $fa-var-hand-back-fist,\n \"hand-rock\": $fa-var-hand-rock,\n \"square-caret-up\": $fa-var-square-caret-up,\n \"caret-square-up\": $fa-var-caret-square-up,\n \"cloud-showers-water\": $fa-var-cloud-showers-water,\n \"chart-bar\": $fa-var-chart-bar,\n \"bar-chart\": $fa-var-bar-chart,\n \"hands-bubbles\": $fa-var-hands-bubbles,\n \"hands-wash\": $fa-var-hands-wash,\n \"less-than-equal\": $fa-var-less-than-equal,\n \"train\": $fa-var-train,\n \"eye-low-vision\": $fa-var-eye-low-vision,\n \"low-vision\": $fa-var-low-vision,\n \"crow\": $fa-var-crow,\n \"sailboat\": $fa-var-sailboat,\n \"window-restore\": $fa-var-window-restore,\n \"square-plus\": $fa-var-square-plus,\n \"plus-square\": $fa-var-plus-square,\n \"torii-gate\": $fa-var-torii-gate,\n \"frog\": $fa-var-frog,\n \"bucket\": $fa-var-bucket,\n \"image\": $fa-var-image,\n \"microphone\": $fa-var-microphone,\n \"cow\": $fa-var-cow,\n \"caret-up\": $fa-var-caret-up,\n \"screwdriver\": $fa-var-screwdriver,\n \"folder-closed\": $fa-var-folder-closed,\n \"house-tsunami\": $fa-var-house-tsunami,\n \"square-nfi\": $fa-var-square-nfi,\n \"arrow-up-from-ground-water\": $fa-var-arrow-up-from-ground-water,\n \"martini-glass\": $fa-var-martini-glass,\n \"glass-martini-alt\": $fa-var-glass-martini-alt,\n \"square-binary\": $fa-var-square-binary,\n \"rotate-left\": $fa-var-rotate-left,\n \"rotate-back\": $fa-var-rotate-back,\n \"rotate-backward\": $fa-var-rotate-backward,\n \"undo-alt\": $fa-var-undo-alt,\n \"table-columns\": $fa-var-table-columns,\n \"columns\": $fa-var-columns,\n \"lemon\": $fa-var-lemon,\n \"head-side-mask\": $fa-var-head-side-mask,\n \"handshake\": $fa-var-handshake,\n \"gem\": $fa-var-gem,\n \"dolly\": $fa-var-dolly,\n \"dolly-box\": $fa-var-dolly-box,\n \"smoking\": $fa-var-smoking,\n \"minimize\": $fa-var-minimize,\n \"compress-arrows-alt\": $fa-var-compress-arrows-alt,\n \"monument\": $fa-var-monument,\n \"snowplow\": $fa-var-snowplow,\n \"angles-right\": $fa-var-angles-right,\n \"angle-double-right\": $fa-var-angle-double-right,\n \"cannabis\": $fa-var-cannabis,\n \"circle-play\": $fa-var-circle-play,\n \"play-circle\": $fa-var-play-circle,\n \"tablets\": $fa-var-tablets,\n \"ethernet\": $fa-var-ethernet,\n \"euro-sign\": $fa-var-euro-sign,\n \"eur\": $fa-var-eur,\n \"euro\": $fa-var-euro,\n \"chair\": $fa-var-chair,\n \"circle-check\": $fa-var-circle-check,\n \"check-circle\": $fa-var-check-circle,\n \"circle-stop\": $fa-var-circle-stop,\n \"stop-circle\": $fa-var-stop-circle,\n \"compass-drafting\": $fa-var-compass-drafting,\n \"drafting-compass\": $fa-var-drafting-compass,\n \"plate-wheat\": $fa-var-plate-wheat,\n \"icicles\": $fa-var-icicles,\n \"person-shelter\": $fa-var-person-shelter,\n \"neuter\": $fa-var-neuter,\n \"id-badge\": $fa-var-id-badge,\n \"marker\": $fa-var-marker,\n \"face-laugh-beam\": $fa-var-face-laugh-beam,\n \"laugh-beam\": $fa-var-laugh-beam,\n \"helicopter-symbol\": $fa-var-helicopter-symbol,\n \"universal-access\": $fa-var-universal-access,\n \"circle-chevron-up\": $fa-var-circle-chevron-up,\n \"chevron-circle-up\": $fa-var-chevron-circle-up,\n \"lari-sign\": $fa-var-lari-sign,\n \"volcano\": $fa-var-volcano,\n \"person-walking-dashed-line-arrow-right\": $fa-var-person-walking-dashed-line-arrow-right,\n \"sterling-sign\": $fa-var-sterling-sign,\n \"gbp\": $fa-var-gbp,\n \"pound-sign\": $fa-var-pound-sign,\n \"viruses\": $fa-var-viruses,\n \"square-person-confined\": $fa-var-square-person-confined,\n \"user-tie\": $fa-var-user-tie,\n \"arrow-down-long\": $fa-var-arrow-down-long,\n \"long-arrow-down\": $fa-var-long-arrow-down,\n \"tent-arrow-down-to-line\": $fa-var-tent-arrow-down-to-line,\n \"certificate\": $fa-var-certificate,\n \"reply-all\": $fa-var-reply-all,\n \"mail-reply-all\": $fa-var-mail-reply-all,\n \"suitcase\": $fa-var-suitcase,\n \"person-skating\": $fa-var-person-skating,\n \"skating\": $fa-var-skating,\n \"filter-circle-dollar\": $fa-var-filter-circle-dollar,\n \"funnel-dollar\": $fa-var-funnel-dollar,\n \"camera-retro\": $fa-var-camera-retro,\n \"circle-arrow-down\": $fa-var-circle-arrow-down,\n \"arrow-circle-down\": $fa-var-arrow-circle-down,\n \"file-import\": $fa-var-file-import,\n \"arrow-right-to-file\": $fa-var-arrow-right-to-file,\n \"square-arrow-up-right\": $fa-var-square-arrow-up-right,\n \"external-link-square\": $fa-var-external-link-square,\n \"box-open\": $fa-var-box-open,\n \"scroll\": $fa-var-scroll,\n \"spa\": $fa-var-spa,\n \"location-pin-lock\": $fa-var-location-pin-lock,\n \"pause\": $fa-var-pause,\n \"hill-avalanche\": $fa-var-hill-avalanche,\n \"temperature-empty\": $fa-var-temperature-empty,\n \"temperature-0\": $fa-var-temperature-0,\n \"thermometer-0\": $fa-var-thermometer-0,\n \"thermometer-empty\": $fa-var-thermometer-empty,\n \"bomb\": $fa-var-bomb,\n \"registered\": $fa-var-registered,\n \"address-card\": $fa-var-address-card,\n \"contact-card\": $fa-var-contact-card,\n \"vcard\": $fa-var-vcard,\n \"scale-unbalanced-flip\": $fa-var-scale-unbalanced-flip,\n \"balance-scale-right\": $fa-var-balance-scale-right,\n \"subscript\": $fa-var-subscript,\n \"diamond-turn-right\": $fa-var-diamond-turn-right,\n \"directions\": $fa-var-directions,\n \"burst\": $fa-var-burst,\n \"house-laptop\": $fa-var-house-laptop,\n \"laptop-house\": $fa-var-laptop-house,\n \"face-tired\": $fa-var-face-tired,\n \"tired\": $fa-var-tired,\n \"money-bills\": $fa-var-money-bills,\n \"smog\": $fa-var-smog,\n \"crutch\": $fa-var-crutch,\n \"cloud-arrow-up\": $fa-var-cloud-arrow-up,\n \"cloud-upload\": $fa-var-cloud-upload,\n \"cloud-upload-alt\": $fa-var-cloud-upload-alt,\n \"palette\": $fa-var-palette,\n \"arrows-turn-right\": $fa-var-arrows-turn-right,\n \"vest\": $fa-var-vest,\n \"ferry\": $fa-var-ferry,\n \"arrows-down-to-people\": $fa-var-arrows-down-to-people,\n \"seedling\": $fa-var-seedling,\n \"sprout\": $fa-var-sprout,\n \"left-right\": $fa-var-left-right,\n \"arrows-alt-h\": $fa-var-arrows-alt-h,\n \"boxes-packing\": $fa-var-boxes-packing,\n \"circle-arrow-left\": $fa-var-circle-arrow-left,\n \"arrow-circle-left\": $fa-var-arrow-circle-left,\n \"group-arrows-rotate\": $fa-var-group-arrows-rotate,\n \"bowl-food\": $fa-var-bowl-food,\n \"candy-cane\": $fa-var-candy-cane,\n \"arrow-down-wide-short\": $fa-var-arrow-down-wide-short,\n \"sort-amount-asc\": $fa-var-sort-amount-asc,\n \"sort-amount-down\": $fa-var-sort-amount-down,\n \"cloud-bolt\": $fa-var-cloud-bolt,\n \"thunderstorm\": $fa-var-thunderstorm,\n \"text-slash\": $fa-var-text-slash,\n \"remove-format\": $fa-var-remove-format,\n \"face-smile-wink\": $fa-var-face-smile-wink,\n \"smile-wink\": $fa-var-smile-wink,\n \"file-word\": $fa-var-file-word,\n \"file-powerpoint\": $fa-var-file-powerpoint,\n \"arrows-left-right\": $fa-var-arrows-left-right,\n \"arrows-h\": $fa-var-arrows-h,\n \"house-lock\": $fa-var-house-lock,\n \"cloud-arrow-down\": $fa-var-cloud-arrow-down,\n \"cloud-download\": $fa-var-cloud-download,\n \"cloud-download-alt\": $fa-var-cloud-download-alt,\n \"children\": $fa-var-children,\n \"chalkboard\": $fa-var-chalkboard,\n \"blackboard\": $fa-var-blackboard,\n \"user-large-slash\": $fa-var-user-large-slash,\n \"user-alt-slash\": $fa-var-user-alt-slash,\n \"envelope-open\": $fa-var-envelope-open,\n \"handshake-simple-slash\": $fa-var-handshake-simple-slash,\n \"handshake-alt-slash\": $fa-var-handshake-alt-slash,\n \"mattress-pillow\": $fa-var-mattress-pillow,\n \"guarani-sign\": $fa-var-guarani-sign,\n \"arrows-rotate\": $fa-var-arrows-rotate,\n \"refresh\": $fa-var-refresh,\n \"sync\": $fa-var-sync,\n \"fire-extinguisher\": $fa-var-fire-extinguisher,\n \"cruzeiro-sign\": $fa-var-cruzeiro-sign,\n \"greater-than-equal\": $fa-var-greater-than-equal,\n \"shield-halved\": $fa-var-shield-halved,\n \"shield-alt\": $fa-var-shield-alt,\n \"book-atlas\": $fa-var-book-atlas,\n \"atlas\": $fa-var-atlas,\n \"virus\": $fa-var-virus,\n \"envelope-circle-check\": $fa-var-envelope-circle-check,\n \"layer-group\": $fa-var-layer-group,\n \"arrows-to-dot\": $fa-var-arrows-to-dot,\n \"archway\": $fa-var-archway,\n \"heart-circle-check\": $fa-var-heart-circle-check,\n \"house-chimney-crack\": $fa-var-house-chimney-crack,\n \"house-damage\": $fa-var-house-damage,\n \"file-zipper\": $fa-var-file-zipper,\n \"file-archive\": $fa-var-file-archive,\n \"square\": $fa-var-square,\n \"martini-glass-empty\": $fa-var-martini-glass-empty,\n \"glass-martini\": $fa-var-glass-martini,\n \"couch\": $fa-var-couch,\n \"cedi-sign\": $fa-var-cedi-sign,\n \"italic\": $fa-var-italic,\n \"table-cells-column-lock\": $fa-var-table-cells-column-lock,\n \"church\": $fa-var-church,\n \"comments-dollar\": $fa-var-comments-dollar,\n \"democrat\": $fa-var-democrat,\n \"z\": $fa-var-z,\n \"person-skiing\": $fa-var-person-skiing,\n \"skiing\": $fa-var-skiing,\n \"road-lock\": $fa-var-road-lock,\n \"a\": $fa-var-a,\n \"temperature-arrow-down\": $fa-var-temperature-arrow-down,\n \"temperature-down\": $fa-var-temperature-down,\n \"feather-pointed\": $fa-var-feather-pointed,\n \"feather-alt\": $fa-var-feather-alt,\n \"p\": $fa-var-p,\n \"snowflake\": $fa-var-snowflake,\n \"newspaper\": $fa-var-newspaper,\n \"rectangle-ad\": $fa-var-rectangle-ad,\n \"ad\": $fa-var-ad,\n \"circle-arrow-right\": $fa-var-circle-arrow-right,\n \"arrow-circle-right\": $fa-var-arrow-circle-right,\n \"filter-circle-xmark\": $fa-var-filter-circle-xmark,\n \"locust\": $fa-var-locust,\n \"sort\": $fa-var-sort,\n \"unsorted\": $fa-var-unsorted,\n \"list-ol\": $fa-var-list-ol,\n \"list-1-2\": $fa-var-list-1-2,\n \"list-numeric\": $fa-var-list-numeric,\n \"person-dress-burst\": $fa-var-person-dress-burst,\n \"money-check-dollar\": $fa-var-money-check-dollar,\n \"money-check-alt\": $fa-var-money-check-alt,\n \"vector-square\": $fa-var-vector-square,\n \"bread-slice\": $fa-var-bread-slice,\n \"language\": $fa-var-language,\n \"face-kiss-wink-heart\": $fa-var-face-kiss-wink-heart,\n \"kiss-wink-heart\": $fa-var-kiss-wink-heart,\n \"filter\": $fa-var-filter,\n \"question\": $fa-var-question,\n \"file-signature\": $fa-var-file-signature,\n \"up-down-left-right\": $fa-var-up-down-left-right,\n \"arrows-alt\": $fa-var-arrows-alt,\n \"house-chimney-user\": $fa-var-house-chimney-user,\n \"hand-holding-heart\": $fa-var-hand-holding-heart,\n \"puzzle-piece\": $fa-var-puzzle-piece,\n \"money-check\": $fa-var-money-check,\n \"star-half-stroke\": $fa-var-star-half-stroke,\n \"star-half-alt\": $fa-var-star-half-alt,\n \"code\": $fa-var-code,\n \"whiskey-glass\": $fa-var-whiskey-glass,\n \"glass-whiskey\": $fa-var-glass-whiskey,\n \"building-circle-exclamation\": $fa-var-building-circle-exclamation,\n \"magnifying-glass-chart\": $fa-var-magnifying-glass-chart,\n \"arrow-up-right-from-square\": $fa-var-arrow-up-right-from-square,\n \"external-link\": $fa-var-external-link,\n \"cubes-stacked\": $fa-var-cubes-stacked,\n \"won-sign\": $fa-var-won-sign,\n \"krw\": $fa-var-krw,\n \"won\": $fa-var-won,\n \"virus-covid\": $fa-var-virus-covid,\n \"austral-sign\": $fa-var-austral-sign,\n \"f\": $fa-var-f,\n \"leaf\": $fa-var-leaf,\n \"road\": $fa-var-road,\n \"taxi\": $fa-var-taxi,\n \"cab\": $fa-var-cab,\n \"person-circle-plus\": $fa-var-person-circle-plus,\n \"chart-pie\": $fa-var-chart-pie,\n \"pie-chart\": $fa-var-pie-chart,\n \"bolt-lightning\": $fa-var-bolt-lightning,\n \"sack-xmark\": $fa-var-sack-xmark,\n \"file-excel\": $fa-var-file-excel,\n \"file-contract\": $fa-var-file-contract,\n \"fish-fins\": $fa-var-fish-fins,\n \"building-flag\": $fa-var-building-flag,\n \"face-grin-beam\": $fa-var-face-grin-beam,\n \"grin-beam\": $fa-var-grin-beam,\n \"object-ungroup\": $fa-var-object-ungroup,\n \"poop\": $fa-var-poop,\n \"location-pin\": $fa-var-location-pin,\n \"map-marker\": $fa-var-map-marker,\n \"kaaba\": $fa-var-kaaba,\n \"toilet-paper\": $fa-var-toilet-paper,\n \"helmet-safety\": $fa-var-helmet-safety,\n \"hard-hat\": $fa-var-hard-hat,\n \"hat-hard\": $fa-var-hat-hard,\n \"eject\": $fa-var-eject,\n \"circle-right\": $fa-var-circle-right,\n \"arrow-alt-circle-right\": $fa-var-arrow-alt-circle-right,\n \"plane-circle-check\": $fa-var-plane-circle-check,\n \"face-rolling-eyes\": $fa-var-face-rolling-eyes,\n \"meh-rolling-eyes\": $fa-var-meh-rolling-eyes,\n \"object-group\": $fa-var-object-group,\n \"chart-line\": $fa-var-chart-line,\n \"line-chart\": $fa-var-line-chart,\n \"mask-ventilator\": $fa-var-mask-ventilator,\n \"arrow-right\": $fa-var-arrow-right,\n \"signs-post\": $fa-var-signs-post,\n \"map-signs\": $fa-var-map-signs,\n \"cash-register\": $fa-var-cash-register,\n \"person-circle-question\": $fa-var-person-circle-question,\n \"h\": $fa-var-h,\n \"tarp\": $fa-var-tarp,\n \"screwdriver-wrench\": $fa-var-screwdriver-wrench,\n \"tools\": $fa-var-tools,\n \"arrows-to-eye\": $fa-var-arrows-to-eye,\n \"plug-circle-bolt\": $fa-var-plug-circle-bolt,\n \"heart\": $fa-var-heart,\n \"mars-and-venus\": $fa-var-mars-and-venus,\n \"house-user\": $fa-var-house-user,\n \"home-user\": $fa-var-home-user,\n \"dumpster-fire\": $fa-var-dumpster-fire,\n \"house-crack\": $fa-var-house-crack,\n \"martini-glass-citrus\": $fa-var-martini-glass-citrus,\n \"cocktail\": $fa-var-cocktail,\n \"face-surprise\": $fa-var-face-surprise,\n \"surprise\": $fa-var-surprise,\n \"bottle-water\": $fa-var-bottle-water,\n \"circle-pause\": $fa-var-circle-pause,\n \"pause-circle\": $fa-var-pause-circle,\n \"toilet-paper-slash\": $fa-var-toilet-paper-slash,\n \"apple-whole\": $fa-var-apple-whole,\n \"apple-alt\": $fa-var-apple-alt,\n \"kitchen-set\": $fa-var-kitchen-set,\n \"r\": $fa-var-r,\n \"temperature-quarter\": $fa-var-temperature-quarter,\n \"temperature-1\": $fa-var-temperature-1,\n \"thermometer-1\": $fa-var-thermometer-1,\n \"thermometer-quarter\": $fa-var-thermometer-quarter,\n \"cube\": $fa-var-cube,\n \"bitcoin-sign\": $fa-var-bitcoin-sign,\n \"shield-dog\": $fa-var-shield-dog,\n \"solar-panel\": $fa-var-solar-panel,\n \"lock-open\": $fa-var-lock-open,\n \"elevator\": $fa-var-elevator,\n \"money-bill-transfer\": $fa-var-money-bill-transfer,\n \"money-bill-trend-up\": $fa-var-money-bill-trend-up,\n \"house-flood-water-circle-arrow-right\": $fa-var-house-flood-water-circle-arrow-right,\n \"square-poll-horizontal\": $fa-var-square-poll-horizontal,\n \"poll-h\": $fa-var-poll-h,\n \"circle\": $fa-var-circle,\n \"backward-fast\": $fa-var-backward-fast,\n \"fast-backward\": $fa-var-fast-backward,\n \"recycle\": $fa-var-recycle,\n \"user-astronaut\": $fa-var-user-astronaut,\n \"plane-slash\": $fa-var-plane-slash,\n \"trademark\": $fa-var-trademark,\n \"basketball\": $fa-var-basketball,\n \"basketball-ball\": $fa-var-basketball-ball,\n \"satellite-dish\": $fa-var-satellite-dish,\n \"circle-up\": $fa-var-circle-up,\n \"arrow-alt-circle-up\": $fa-var-arrow-alt-circle-up,\n \"mobile-screen-button\": $fa-var-mobile-screen-button,\n \"mobile-alt\": $fa-var-mobile-alt,\n \"volume-high\": $fa-var-volume-high,\n \"volume-up\": $fa-var-volume-up,\n \"users-rays\": $fa-var-users-rays,\n \"wallet\": $fa-var-wallet,\n \"clipboard-check\": $fa-var-clipboard-check,\n \"file-audio\": $fa-var-file-audio,\n \"burger\": $fa-var-burger,\n \"hamburger\": $fa-var-hamburger,\n \"wrench\": $fa-var-wrench,\n \"bugs\": $fa-var-bugs,\n \"rupee-sign\": $fa-var-rupee-sign,\n \"rupee\": $fa-var-rupee,\n \"file-image\": $fa-var-file-image,\n \"circle-question\": $fa-var-circle-question,\n \"question-circle\": $fa-var-question-circle,\n \"plane-departure\": $fa-var-plane-departure,\n \"handshake-slash\": $fa-var-handshake-slash,\n \"book-bookmark\": $fa-var-book-bookmark,\n \"code-branch\": $fa-var-code-branch,\n \"hat-cowboy\": $fa-var-hat-cowboy,\n \"bridge\": $fa-var-bridge,\n \"phone-flip\": $fa-var-phone-flip,\n \"phone-alt\": $fa-var-phone-alt,\n \"truck-front\": $fa-var-truck-front,\n \"cat\": $fa-var-cat,\n \"anchor-circle-exclamation\": $fa-var-anchor-circle-exclamation,\n \"truck-field\": $fa-var-truck-field,\n \"route\": $fa-var-route,\n \"clipboard-question\": $fa-var-clipboard-question,\n \"panorama\": $fa-var-panorama,\n \"comment-medical\": $fa-var-comment-medical,\n \"teeth-open\": $fa-var-teeth-open,\n \"file-circle-minus\": $fa-var-file-circle-minus,\n \"tags\": $fa-var-tags,\n \"wine-glass\": $fa-var-wine-glass,\n \"forward-fast\": $fa-var-forward-fast,\n \"fast-forward\": $fa-var-fast-forward,\n \"face-meh-blank\": $fa-var-face-meh-blank,\n \"meh-blank\": $fa-var-meh-blank,\n \"square-parking\": $fa-var-square-parking,\n \"parking\": $fa-var-parking,\n \"house-signal\": $fa-var-house-signal,\n \"bars-progress\": $fa-var-bars-progress,\n \"tasks-alt\": $fa-var-tasks-alt,\n \"faucet-drip\": $fa-var-faucet-drip,\n \"cart-flatbed\": $fa-var-cart-flatbed,\n \"dolly-flatbed\": $fa-var-dolly-flatbed,\n \"ban-smoking\": $fa-var-ban-smoking,\n \"smoking-ban\": $fa-var-smoking-ban,\n \"terminal\": $fa-var-terminal,\n \"mobile-button\": $fa-var-mobile-button,\n \"house-medical-flag\": $fa-var-house-medical-flag,\n \"basket-shopping\": $fa-var-basket-shopping,\n \"shopping-basket\": $fa-var-shopping-basket,\n \"tape\": $fa-var-tape,\n \"bus-simple\": $fa-var-bus-simple,\n \"bus-alt\": $fa-var-bus-alt,\n \"eye\": $fa-var-eye,\n \"face-sad-cry\": $fa-var-face-sad-cry,\n \"sad-cry\": $fa-var-sad-cry,\n \"audio-description\": $fa-var-audio-description,\n \"person-military-to-person\": $fa-var-person-military-to-person,\n \"file-shield\": $fa-var-file-shield,\n \"user-slash\": $fa-var-user-slash,\n \"pen\": $fa-var-pen,\n \"tower-observation\": $fa-var-tower-observation,\n \"file-code\": $fa-var-file-code,\n \"signal\": $fa-var-signal,\n \"signal-5\": $fa-var-signal-5,\n \"signal-perfect\": $fa-var-signal-perfect,\n \"bus\": $fa-var-bus,\n \"heart-circle-xmark\": $fa-var-heart-circle-xmark,\n \"house-chimney\": $fa-var-house-chimney,\n \"home-lg\": $fa-var-home-lg,\n \"window-maximize\": $fa-var-window-maximize,\n \"face-frown\": $fa-var-face-frown,\n \"frown\": $fa-var-frown,\n \"prescription\": $fa-var-prescription,\n \"shop\": $fa-var-shop,\n \"store-alt\": $fa-var-store-alt,\n \"floppy-disk\": $fa-var-floppy-disk,\n \"save\": $fa-var-save,\n \"vihara\": $fa-var-vihara,\n \"scale-unbalanced\": $fa-var-scale-unbalanced,\n \"balance-scale-left\": $fa-var-balance-scale-left,\n \"sort-up\": $fa-var-sort-up,\n \"sort-asc\": $fa-var-sort-asc,\n \"comment-dots\": $fa-var-comment-dots,\n \"commenting\": $fa-var-commenting,\n \"plant-wilt\": $fa-var-plant-wilt,\n \"diamond\": $fa-var-diamond,\n \"face-grin-squint\": $fa-var-face-grin-squint,\n \"grin-squint\": $fa-var-grin-squint,\n \"hand-holding-dollar\": $fa-var-hand-holding-dollar,\n \"hand-holding-usd\": $fa-var-hand-holding-usd,\n \"chart-diagram\": $fa-var-chart-diagram,\n \"bacterium\": $fa-var-bacterium,\n \"hand-pointer\": $fa-var-hand-pointer,\n \"drum-steelpan\": $fa-var-drum-steelpan,\n \"hand-scissors\": $fa-var-hand-scissors,\n \"hands-praying\": $fa-var-hands-praying,\n \"praying-hands\": $fa-var-praying-hands,\n \"arrow-rotate-right\": $fa-var-arrow-rotate-right,\n \"arrow-right-rotate\": $fa-var-arrow-right-rotate,\n \"arrow-rotate-forward\": $fa-var-arrow-rotate-forward,\n \"redo\": $fa-var-redo,\n \"biohazard\": $fa-var-biohazard,\n \"location-crosshairs\": $fa-var-location-crosshairs,\n \"location\": $fa-var-location,\n \"mars-double\": $fa-var-mars-double,\n \"child-dress\": $fa-var-child-dress,\n \"users-between-lines\": $fa-var-users-between-lines,\n \"lungs-virus\": $fa-var-lungs-virus,\n \"face-grin-tears\": $fa-var-face-grin-tears,\n \"grin-tears\": $fa-var-grin-tears,\n \"phone\": $fa-var-phone,\n \"calendar-xmark\": $fa-var-calendar-xmark,\n \"calendar-times\": $fa-var-calendar-times,\n \"child-reaching\": $fa-var-child-reaching,\n \"head-side-virus\": $fa-var-head-side-virus,\n \"user-gear\": $fa-var-user-gear,\n \"user-cog\": $fa-var-user-cog,\n \"arrow-up-1-9\": $fa-var-arrow-up-1-9,\n \"sort-numeric-up\": $fa-var-sort-numeric-up,\n \"door-closed\": $fa-var-door-closed,\n \"shield-virus\": $fa-var-shield-virus,\n \"dice-six\": $fa-var-dice-six,\n \"mosquito-net\": $fa-var-mosquito-net,\n \"file-fragment\": $fa-var-file-fragment,\n \"bridge-water\": $fa-var-bridge-water,\n \"person-booth\": $fa-var-person-booth,\n \"text-width\": $fa-var-text-width,\n \"hat-wizard\": $fa-var-hat-wizard,\n \"pen-fancy\": $fa-var-pen-fancy,\n \"person-digging\": $fa-var-person-digging,\n \"digging\": $fa-var-digging,\n \"trash\": $fa-var-trash,\n \"gauge-simple\": $fa-var-gauge-simple,\n \"gauge-simple-med\": $fa-var-gauge-simple-med,\n \"tachometer-average\": $fa-var-tachometer-average,\n \"book-medical\": $fa-var-book-medical,\n \"poo\": $fa-var-poo,\n \"quote-right\": $fa-var-quote-right,\n \"quote-right-alt\": $fa-var-quote-right-alt,\n \"shirt\": $fa-var-shirt,\n \"t-shirt\": $fa-var-t-shirt,\n \"tshirt\": $fa-var-tshirt,\n \"cubes\": $fa-var-cubes,\n \"divide\": $fa-var-divide,\n \"tenge-sign\": $fa-var-tenge-sign,\n \"tenge\": $fa-var-tenge,\n \"headphones\": $fa-var-headphones,\n \"hands-holding\": $fa-var-hands-holding,\n \"hands-clapping\": $fa-var-hands-clapping,\n \"republican\": $fa-var-republican,\n \"arrow-left\": $fa-var-arrow-left,\n \"person-circle-xmark\": $fa-var-person-circle-xmark,\n \"ruler\": $fa-var-ruler,\n \"align-left\": $fa-var-align-left,\n \"dice-d6\": $fa-var-dice-d6,\n \"restroom\": $fa-var-restroom,\n \"j\": $fa-var-j,\n \"users-viewfinder\": $fa-var-users-viewfinder,\n \"file-video\": $fa-var-file-video,\n \"up-right-from-square\": $fa-var-up-right-from-square,\n \"external-link-alt\": $fa-var-external-link-alt,\n \"table-cells\": $fa-var-table-cells,\n \"th\": $fa-var-th,\n \"file-pdf\": $fa-var-file-pdf,\n \"book-bible\": $fa-var-book-bible,\n \"bible\": $fa-var-bible,\n \"o\": $fa-var-o,\n \"suitcase-medical\": $fa-var-suitcase-medical,\n \"medkit\": $fa-var-medkit,\n \"user-secret\": $fa-var-user-secret,\n \"otter\": $fa-var-otter,\n \"person-dress\": $fa-var-person-dress,\n \"female\": $fa-var-female,\n \"comment-dollar\": $fa-var-comment-dollar,\n \"business-time\": $fa-var-business-time,\n \"briefcase-clock\": $fa-var-briefcase-clock,\n \"table-cells-large\": $fa-var-table-cells-large,\n \"th-large\": $fa-var-th-large,\n \"book-tanakh\": $fa-var-book-tanakh,\n \"tanakh\": $fa-var-tanakh,\n \"phone-volume\": $fa-var-phone-volume,\n \"volume-control-phone\": $fa-var-volume-control-phone,\n \"hat-cowboy-side\": $fa-var-hat-cowboy-side,\n \"clipboard-user\": $fa-var-clipboard-user,\n \"child\": $fa-var-child,\n \"lira-sign\": $fa-var-lira-sign,\n \"satellite\": $fa-var-satellite,\n \"plane-lock\": $fa-var-plane-lock,\n \"tag\": $fa-var-tag,\n \"comment\": $fa-var-comment,\n \"cake-candles\": $fa-var-cake-candles,\n \"birthday-cake\": $fa-var-birthday-cake,\n \"cake\": $fa-var-cake,\n \"envelope\": $fa-var-envelope,\n \"angles-up\": $fa-var-angles-up,\n \"angle-double-up\": $fa-var-angle-double-up,\n \"paperclip\": $fa-var-paperclip,\n \"arrow-right-to-city\": $fa-var-arrow-right-to-city,\n \"ribbon\": $fa-var-ribbon,\n \"lungs\": $fa-var-lungs,\n \"arrow-up-9-1\": $fa-var-arrow-up-9-1,\n \"sort-numeric-up-alt\": $fa-var-sort-numeric-up-alt,\n \"litecoin-sign\": $fa-var-litecoin-sign,\n \"border-none\": $fa-var-border-none,\n \"circle-nodes\": $fa-var-circle-nodes,\n \"parachute-box\": $fa-var-parachute-box,\n \"indent\": $fa-var-indent,\n \"truck-field-un\": $fa-var-truck-field-un,\n \"hourglass\": $fa-var-hourglass,\n \"hourglass-empty\": $fa-var-hourglass-empty,\n \"mountain\": $fa-var-mountain,\n \"user-doctor\": $fa-var-user-doctor,\n \"user-md\": $fa-var-user-md,\n \"circle-info\": $fa-var-circle-info,\n \"info-circle\": $fa-var-info-circle,\n \"cloud-meatball\": $fa-var-cloud-meatball,\n \"camera\": $fa-var-camera,\n \"camera-alt\": $fa-var-camera-alt,\n \"square-virus\": $fa-var-square-virus,\n \"meteor\": $fa-var-meteor,\n \"car-on\": $fa-var-car-on,\n \"sleigh\": $fa-var-sleigh,\n \"arrow-down-1-9\": $fa-var-arrow-down-1-9,\n \"sort-numeric-asc\": $fa-var-sort-numeric-asc,\n \"sort-numeric-down\": $fa-var-sort-numeric-down,\n \"hand-holding-droplet\": $fa-var-hand-holding-droplet,\n \"hand-holding-water\": $fa-var-hand-holding-water,\n \"water\": $fa-var-water,\n \"calendar-check\": $fa-var-calendar-check,\n \"braille\": $fa-var-braille,\n \"prescription-bottle-medical\": $fa-var-prescription-bottle-medical,\n \"prescription-bottle-alt\": $fa-var-prescription-bottle-alt,\n \"landmark\": $fa-var-landmark,\n \"truck\": $fa-var-truck,\n \"crosshairs\": $fa-var-crosshairs,\n \"person-cane\": $fa-var-person-cane,\n \"tent\": $fa-var-tent,\n \"vest-patches\": $fa-var-vest-patches,\n \"check-double\": $fa-var-check-double,\n \"arrow-down-a-z\": $fa-var-arrow-down-a-z,\n \"sort-alpha-asc\": $fa-var-sort-alpha-asc,\n \"sort-alpha-down\": $fa-var-sort-alpha-down,\n \"money-bill-wheat\": $fa-var-money-bill-wheat,\n \"cookie\": $fa-var-cookie,\n \"arrow-rotate-left\": $fa-var-arrow-rotate-left,\n \"arrow-left-rotate\": $fa-var-arrow-left-rotate,\n \"arrow-rotate-back\": $fa-var-arrow-rotate-back,\n \"arrow-rotate-backward\": $fa-var-arrow-rotate-backward,\n \"undo\": $fa-var-undo,\n \"hard-drive\": $fa-var-hard-drive,\n \"hdd\": $fa-var-hdd,\n \"face-grin-squint-tears\": $fa-var-face-grin-squint-tears,\n \"grin-squint-tears\": $fa-var-grin-squint-tears,\n \"dumbbell\": $fa-var-dumbbell,\n \"rectangle-list\": $fa-var-rectangle-list,\n \"list-alt\": $fa-var-list-alt,\n \"tarp-droplet\": $fa-var-tarp-droplet,\n \"house-medical-circle-check\": $fa-var-house-medical-circle-check,\n \"person-skiing-nordic\": $fa-var-person-skiing-nordic,\n \"skiing-nordic\": $fa-var-skiing-nordic,\n \"calendar-plus\": $fa-var-calendar-plus,\n \"plane-arrival\": $fa-var-plane-arrival,\n \"circle-left\": $fa-var-circle-left,\n \"arrow-alt-circle-left\": $fa-var-arrow-alt-circle-left,\n \"train-subway\": $fa-var-train-subway,\n \"subway\": $fa-var-subway,\n \"chart-gantt\": $fa-var-chart-gantt,\n \"indian-rupee-sign\": $fa-var-indian-rupee-sign,\n \"indian-rupee\": $fa-var-indian-rupee,\n \"inr\": $fa-var-inr,\n \"crop-simple\": $fa-var-crop-simple,\n \"crop-alt\": $fa-var-crop-alt,\n \"money-bill-1\": $fa-var-money-bill-1,\n \"money-bill-alt\": $fa-var-money-bill-alt,\n \"left-long\": $fa-var-left-long,\n \"long-arrow-alt-left\": $fa-var-long-arrow-alt-left,\n \"dna\": $fa-var-dna,\n \"virus-slash\": $fa-var-virus-slash,\n \"minus\": $fa-var-minus,\n \"subtract\": $fa-var-subtract,\n \"chess\": $fa-var-chess,\n \"arrow-left-long\": $fa-var-arrow-left-long,\n \"long-arrow-left\": $fa-var-long-arrow-left,\n \"plug-circle-check\": $fa-var-plug-circle-check,\n \"street-view\": $fa-var-street-view,\n \"franc-sign\": $fa-var-franc-sign,\n \"volume-off\": $fa-var-volume-off,\n \"hands-asl-interpreting\": $fa-var-hands-asl-interpreting,\n \"american-sign-language-interpreting\": $fa-var-american-sign-language-interpreting,\n \"asl-interpreting\": $fa-var-asl-interpreting,\n \"hands-american-sign-language-interpreting\": $fa-var-hands-american-sign-language-interpreting,\n \"gear\": $fa-var-gear,\n \"cog\": $fa-var-cog,\n \"droplet-slash\": $fa-var-droplet-slash,\n \"tint-slash\": $fa-var-tint-slash,\n \"mosque\": $fa-var-mosque,\n \"mosquito\": $fa-var-mosquito,\n \"star-of-david\": $fa-var-star-of-david,\n \"person-military-rifle\": $fa-var-person-military-rifle,\n \"cart-shopping\": $fa-var-cart-shopping,\n \"shopping-cart\": $fa-var-shopping-cart,\n \"vials\": $fa-var-vials,\n \"plug-circle-plus\": $fa-var-plug-circle-plus,\n \"place-of-worship\": $fa-var-place-of-worship,\n \"grip-vertical\": $fa-var-grip-vertical,\n \"hexagon-nodes\": $fa-var-hexagon-nodes,\n \"arrow-turn-up\": $fa-var-arrow-turn-up,\n \"level-up\": $fa-var-level-up,\n \"u\": $fa-var-u,\n \"square-root-variable\": $fa-var-square-root-variable,\n \"square-root-alt\": $fa-var-square-root-alt,\n \"clock\": $fa-var-clock,\n \"clock-four\": $fa-var-clock-four,\n \"backward-step\": $fa-var-backward-step,\n \"step-backward\": $fa-var-step-backward,\n \"pallet\": $fa-var-pallet,\n \"faucet\": $fa-var-faucet,\n \"baseball-bat-ball\": $fa-var-baseball-bat-ball,\n \"s\": $fa-var-s,\n \"timeline\": $fa-var-timeline,\n \"keyboard\": $fa-var-keyboard,\n \"caret-down\": $fa-var-caret-down,\n \"house-chimney-medical\": $fa-var-house-chimney-medical,\n \"clinic-medical\": $fa-var-clinic-medical,\n \"temperature-three-quarters\": $fa-var-temperature-three-quarters,\n \"temperature-3\": $fa-var-temperature-3,\n \"thermometer-3\": $fa-var-thermometer-3,\n \"thermometer-three-quarters\": $fa-var-thermometer-three-quarters,\n \"mobile-screen\": $fa-var-mobile-screen,\n \"mobile-android-alt\": $fa-var-mobile-android-alt,\n \"plane-up\": $fa-var-plane-up,\n \"piggy-bank\": $fa-var-piggy-bank,\n \"battery-half\": $fa-var-battery-half,\n \"battery-3\": $fa-var-battery-3,\n \"mountain-city\": $fa-var-mountain-city,\n \"coins\": $fa-var-coins,\n \"khanda\": $fa-var-khanda,\n \"sliders\": $fa-var-sliders,\n \"sliders-h\": $fa-var-sliders-h,\n \"folder-tree\": $fa-var-folder-tree,\n \"network-wired\": $fa-var-network-wired,\n \"map-pin\": $fa-var-map-pin,\n \"hamsa\": $fa-var-hamsa,\n \"cent-sign\": $fa-var-cent-sign,\n \"flask\": $fa-var-flask,\n \"person-pregnant\": $fa-var-person-pregnant,\n \"wand-sparkles\": $fa-var-wand-sparkles,\n \"ellipsis-vertical\": $fa-var-ellipsis-vertical,\n \"ellipsis-v\": $fa-var-ellipsis-v,\n \"ticket\": $fa-var-ticket,\n \"power-off\": $fa-var-power-off,\n \"right-long\": $fa-var-right-long,\n \"long-arrow-alt-right\": $fa-var-long-arrow-alt-right,\n \"flag-usa\": $fa-var-flag-usa,\n \"laptop-file\": $fa-var-laptop-file,\n \"tty\": $fa-var-tty,\n \"teletype\": $fa-var-teletype,\n \"diagram-next\": $fa-var-diagram-next,\n \"person-rifle\": $fa-var-person-rifle,\n \"house-medical-circle-exclamation\": $fa-var-house-medical-circle-exclamation,\n \"closed-captioning\": $fa-var-closed-captioning,\n \"person-hiking\": $fa-var-person-hiking,\n \"hiking\": $fa-var-hiking,\n \"venus-double\": $fa-var-venus-double,\n \"images\": $fa-var-images,\n \"calculator\": $fa-var-calculator,\n \"people-pulling\": $fa-var-people-pulling,\n \"n\": $fa-var-n,\n \"cable-car\": $fa-var-cable-car,\n \"tram\": $fa-var-tram,\n \"cloud-rain\": $fa-var-cloud-rain,\n \"building-circle-xmark\": $fa-var-building-circle-xmark,\n \"ship\": $fa-var-ship,\n \"arrows-down-to-line\": $fa-var-arrows-down-to-line,\n \"download\": $fa-var-download,\n \"face-grin\": $fa-var-face-grin,\n \"grin\": $fa-var-grin,\n \"delete-left\": $fa-var-delete-left,\n \"backspace\": $fa-var-backspace,\n \"eye-dropper\": $fa-var-eye-dropper,\n \"eye-dropper-empty\": $fa-var-eye-dropper-empty,\n \"eyedropper\": $fa-var-eyedropper,\n \"file-circle-check\": $fa-var-file-circle-check,\n \"forward\": $fa-var-forward,\n \"mobile\": $fa-var-mobile,\n \"mobile-android\": $fa-var-mobile-android,\n \"mobile-phone\": $fa-var-mobile-phone,\n \"face-meh\": $fa-var-face-meh,\n \"meh\": $fa-var-meh,\n \"align-center\": $fa-var-align-center,\n \"book-skull\": $fa-var-book-skull,\n \"book-dead\": $fa-var-book-dead,\n \"id-card\": $fa-var-id-card,\n \"drivers-license\": $fa-var-drivers-license,\n \"outdent\": $fa-var-outdent,\n \"dedent\": $fa-var-dedent,\n \"heart-circle-exclamation\": $fa-var-heart-circle-exclamation,\n \"house\": $fa-var-house,\n \"home\": $fa-var-home,\n \"home-alt\": $fa-var-home-alt,\n \"home-lg-alt\": $fa-var-home-lg-alt,\n \"calendar-week\": $fa-var-calendar-week,\n \"laptop-medical\": $fa-var-laptop-medical,\n \"b\": $fa-var-b,\n \"file-medical\": $fa-var-file-medical,\n \"dice-one\": $fa-var-dice-one,\n \"kiwi-bird\": $fa-var-kiwi-bird,\n \"arrow-right-arrow-left\": $fa-var-arrow-right-arrow-left,\n \"exchange\": $fa-var-exchange,\n \"rotate-right\": $fa-var-rotate-right,\n \"redo-alt\": $fa-var-redo-alt,\n \"rotate-forward\": $fa-var-rotate-forward,\n \"utensils\": $fa-var-utensils,\n \"cutlery\": $fa-var-cutlery,\n \"arrow-up-wide-short\": $fa-var-arrow-up-wide-short,\n \"sort-amount-up\": $fa-var-sort-amount-up,\n \"mill-sign\": $fa-var-mill-sign,\n \"bowl-rice\": $fa-var-bowl-rice,\n \"skull\": $fa-var-skull,\n \"tower-broadcast\": $fa-var-tower-broadcast,\n \"broadcast-tower\": $fa-var-broadcast-tower,\n \"truck-pickup\": $fa-var-truck-pickup,\n \"up-long\": $fa-var-up-long,\n \"long-arrow-alt-up\": $fa-var-long-arrow-alt-up,\n \"stop\": $fa-var-stop,\n \"code-merge\": $fa-var-code-merge,\n \"upload\": $fa-var-upload,\n \"hurricane\": $fa-var-hurricane,\n \"mound\": $fa-var-mound,\n \"toilet-portable\": $fa-var-toilet-portable,\n \"compact-disc\": $fa-var-compact-disc,\n \"file-arrow-down\": $fa-var-file-arrow-down,\n \"file-download\": $fa-var-file-download,\n \"caravan\": $fa-var-caravan,\n \"shield-cat\": $fa-var-shield-cat,\n \"bolt\": $fa-var-bolt,\n \"zap\": $fa-var-zap,\n \"glass-water\": $fa-var-glass-water,\n \"oil-well\": $fa-var-oil-well,\n \"vault\": $fa-var-vault,\n \"mars\": $fa-var-mars,\n \"toilet\": $fa-var-toilet,\n \"plane-circle-xmark\": $fa-var-plane-circle-xmark,\n \"yen-sign\": $fa-var-yen-sign,\n \"cny\": $fa-var-cny,\n \"jpy\": $fa-var-jpy,\n \"rmb\": $fa-var-rmb,\n \"yen\": $fa-var-yen,\n \"ruble-sign\": $fa-var-ruble-sign,\n \"rouble\": $fa-var-rouble,\n \"rub\": $fa-var-rub,\n \"ruble\": $fa-var-ruble,\n \"sun\": $fa-var-sun,\n \"guitar\": $fa-var-guitar,\n \"face-laugh-wink\": $fa-var-face-laugh-wink,\n \"laugh-wink\": $fa-var-laugh-wink,\n \"horse-head\": $fa-var-horse-head,\n \"bore-hole\": $fa-var-bore-hole,\n \"industry\": $fa-var-industry,\n \"circle-down\": $fa-var-circle-down,\n \"arrow-alt-circle-down\": $fa-var-arrow-alt-circle-down,\n \"arrows-turn-to-dots\": $fa-var-arrows-turn-to-dots,\n \"florin-sign\": $fa-var-florin-sign,\n \"arrow-down-short-wide\": $fa-var-arrow-down-short-wide,\n \"sort-amount-desc\": $fa-var-sort-amount-desc,\n \"sort-amount-down-alt\": $fa-var-sort-amount-down-alt,\n \"less-than\": $fa-var-less-than,\n \"angle-down\": $fa-var-angle-down,\n \"car-tunnel\": $fa-var-car-tunnel,\n \"head-side-cough\": $fa-var-head-side-cough,\n \"grip-lines\": $fa-var-grip-lines,\n \"thumbs-down\": $fa-var-thumbs-down,\n \"user-lock\": $fa-var-user-lock,\n \"arrow-right-long\": $fa-var-arrow-right-long,\n \"long-arrow-right\": $fa-var-long-arrow-right,\n \"anchor-circle-xmark\": $fa-var-anchor-circle-xmark,\n \"ellipsis\": $fa-var-ellipsis,\n \"ellipsis-h\": $fa-var-ellipsis-h,\n \"chess-pawn\": $fa-var-chess-pawn,\n \"kit-medical\": $fa-var-kit-medical,\n \"first-aid\": $fa-var-first-aid,\n \"person-through-window\": $fa-var-person-through-window,\n \"toolbox\": $fa-var-toolbox,\n \"hands-holding-circle\": $fa-var-hands-holding-circle,\n \"bug\": $fa-var-bug,\n \"credit-card\": $fa-var-credit-card,\n \"credit-card-alt\": $fa-var-credit-card-alt,\n \"car\": $fa-var-car,\n \"automobile\": $fa-var-automobile,\n \"hand-holding-hand\": $fa-var-hand-holding-hand,\n \"book-open-reader\": $fa-var-book-open-reader,\n \"book-reader\": $fa-var-book-reader,\n \"mountain-sun\": $fa-var-mountain-sun,\n \"arrows-left-right-to-line\": $fa-var-arrows-left-right-to-line,\n \"dice-d20\": $fa-var-dice-d20,\n \"truck-droplet\": $fa-var-truck-droplet,\n \"file-circle-xmark\": $fa-var-file-circle-xmark,\n \"temperature-arrow-up\": $fa-var-temperature-arrow-up,\n \"temperature-up\": $fa-var-temperature-up,\n \"medal\": $fa-var-medal,\n \"bed\": $fa-var-bed,\n \"square-h\": $fa-var-square-h,\n \"h-square\": $fa-var-h-square,\n \"podcast\": $fa-var-podcast,\n \"temperature-full\": $fa-var-temperature-full,\n \"temperature-4\": $fa-var-temperature-4,\n \"thermometer-4\": $fa-var-thermometer-4,\n \"thermometer-full\": $fa-var-thermometer-full,\n \"bell\": $fa-var-bell,\n \"superscript\": $fa-var-superscript,\n \"plug-circle-xmark\": $fa-var-plug-circle-xmark,\n \"star-of-life\": $fa-var-star-of-life,\n \"phone-slash\": $fa-var-phone-slash,\n \"paint-roller\": $fa-var-paint-roller,\n \"handshake-angle\": $fa-var-handshake-angle,\n \"hands-helping\": $fa-var-hands-helping,\n \"location-dot\": $fa-var-location-dot,\n \"map-marker-alt\": $fa-var-map-marker-alt,\n \"file\": $fa-var-file,\n \"greater-than\": $fa-var-greater-than,\n \"person-swimming\": $fa-var-person-swimming,\n \"swimmer\": $fa-var-swimmer,\n \"arrow-down\": $fa-var-arrow-down,\n \"droplet\": $fa-var-droplet,\n \"tint\": $fa-var-tint,\n \"eraser\": $fa-var-eraser,\n \"earth-americas\": $fa-var-earth-americas,\n \"earth\": $fa-var-earth,\n \"earth-america\": $fa-var-earth-america,\n \"globe-americas\": $fa-var-globe-americas,\n \"person-burst\": $fa-var-person-burst,\n \"dove\": $fa-var-dove,\n \"battery-empty\": $fa-var-battery-empty,\n \"battery-0\": $fa-var-battery-0,\n \"socks\": $fa-var-socks,\n \"inbox\": $fa-var-inbox,\n \"section\": $fa-var-section,\n \"gauge-high\": $fa-var-gauge-high,\n \"tachometer-alt\": $fa-var-tachometer-alt,\n \"tachometer-alt-fast\": $fa-var-tachometer-alt-fast,\n \"envelope-open-text\": $fa-var-envelope-open-text,\n \"hospital\": $fa-var-hospital,\n \"hospital-alt\": $fa-var-hospital-alt,\n \"hospital-wide\": $fa-var-hospital-wide,\n \"wine-bottle\": $fa-var-wine-bottle,\n \"chess-rook\": $fa-var-chess-rook,\n \"bars-staggered\": $fa-var-bars-staggered,\n \"reorder\": $fa-var-reorder,\n \"stream\": $fa-var-stream,\n \"dharmachakra\": $fa-var-dharmachakra,\n \"hotdog\": $fa-var-hotdog,\n \"person-walking-with-cane\": $fa-var-person-walking-with-cane,\n \"blind\": $fa-var-blind,\n \"drum\": $fa-var-drum,\n \"ice-cream\": $fa-var-ice-cream,\n \"heart-circle-bolt\": $fa-var-heart-circle-bolt,\n \"fax\": $fa-var-fax,\n \"paragraph\": $fa-var-paragraph,\n \"check-to-slot\": $fa-var-check-to-slot,\n \"vote-yea\": $fa-var-vote-yea,\n \"star-half\": $fa-var-star-half,\n \"boxes-stacked\": $fa-var-boxes-stacked,\n \"boxes\": $fa-var-boxes,\n \"boxes-alt\": $fa-var-boxes-alt,\n \"link\": $fa-var-link,\n \"chain\": $fa-var-chain,\n \"ear-listen\": $fa-var-ear-listen,\n \"assistive-listening-systems\": $fa-var-assistive-listening-systems,\n \"tree-city\": $fa-var-tree-city,\n \"play\": $fa-var-play,\n \"font\": $fa-var-font,\n \"table-cells-row-lock\": $fa-var-table-cells-row-lock,\n \"rupiah-sign\": $fa-var-rupiah-sign,\n \"magnifying-glass\": $fa-var-magnifying-glass,\n \"search\": $fa-var-search,\n \"table-tennis-paddle-ball\": $fa-var-table-tennis-paddle-ball,\n \"ping-pong-paddle-ball\": $fa-var-ping-pong-paddle-ball,\n \"table-tennis\": $fa-var-table-tennis,\n \"person-dots-from-line\": $fa-var-person-dots-from-line,\n \"diagnoses\": $fa-var-diagnoses,\n \"trash-can-arrow-up\": $fa-var-trash-can-arrow-up,\n \"trash-restore-alt\": $fa-var-trash-restore-alt,\n \"naira-sign\": $fa-var-naira-sign,\n \"cart-arrow-down\": $fa-var-cart-arrow-down,\n \"walkie-talkie\": $fa-var-walkie-talkie,\n \"file-pen\": $fa-var-file-pen,\n \"file-edit\": $fa-var-file-edit,\n \"receipt\": $fa-var-receipt,\n \"square-pen\": $fa-var-square-pen,\n \"pen-square\": $fa-var-pen-square,\n \"pencil-square\": $fa-var-pencil-square,\n \"suitcase-rolling\": $fa-var-suitcase-rolling,\n \"person-circle-exclamation\": $fa-var-person-circle-exclamation,\n \"chevron-down\": $fa-var-chevron-down,\n \"battery-full\": $fa-var-battery-full,\n \"battery\": $fa-var-battery,\n \"battery-5\": $fa-var-battery-5,\n \"skull-crossbones\": $fa-var-skull-crossbones,\n \"code-compare\": $fa-var-code-compare,\n \"list-ul\": $fa-var-list-ul,\n \"list-dots\": $fa-var-list-dots,\n \"school-lock\": $fa-var-school-lock,\n \"tower-cell\": $fa-var-tower-cell,\n \"down-long\": $fa-var-down-long,\n \"long-arrow-alt-down\": $fa-var-long-arrow-alt-down,\n \"ranking-star\": $fa-var-ranking-star,\n \"chess-king\": $fa-var-chess-king,\n \"person-harassing\": $fa-var-person-harassing,\n \"brazilian-real-sign\": $fa-var-brazilian-real-sign,\n \"landmark-dome\": $fa-var-landmark-dome,\n \"landmark-alt\": $fa-var-landmark-alt,\n \"arrow-up\": $fa-var-arrow-up,\n \"tv\": $fa-var-tv,\n \"television\": $fa-var-television,\n \"tv-alt\": $fa-var-tv-alt,\n \"shrimp\": $fa-var-shrimp,\n \"list-check\": $fa-var-list-check,\n \"tasks\": $fa-var-tasks,\n \"jug-detergent\": $fa-var-jug-detergent,\n \"circle-user\": $fa-var-circle-user,\n \"user-circle\": $fa-var-user-circle,\n \"user-shield\": $fa-var-user-shield,\n \"wind\": $fa-var-wind,\n \"car-burst\": $fa-var-car-burst,\n \"car-crash\": $fa-var-car-crash,\n \"y\": $fa-var-y,\n \"person-snowboarding\": $fa-var-person-snowboarding,\n \"snowboarding\": $fa-var-snowboarding,\n \"truck-fast\": $fa-var-truck-fast,\n \"shipping-fast\": $fa-var-shipping-fast,\n \"fish\": $fa-var-fish,\n \"user-graduate\": $fa-var-user-graduate,\n \"circle-half-stroke\": $fa-var-circle-half-stroke,\n \"adjust\": $fa-var-adjust,\n \"clapperboard\": $fa-var-clapperboard,\n \"circle-radiation\": $fa-var-circle-radiation,\n \"radiation-alt\": $fa-var-radiation-alt,\n \"baseball\": $fa-var-baseball,\n \"baseball-ball\": $fa-var-baseball-ball,\n \"jet-fighter-up\": $fa-var-jet-fighter-up,\n \"diagram-project\": $fa-var-diagram-project,\n \"project-diagram\": $fa-var-project-diagram,\n \"copy\": $fa-var-copy,\n \"volume-xmark\": $fa-var-volume-xmark,\n \"volume-mute\": $fa-var-volume-mute,\n \"volume-times\": $fa-var-volume-times,\n \"hand-sparkles\": $fa-var-hand-sparkles,\n \"grip\": $fa-var-grip,\n \"grip-horizontal\": $fa-var-grip-horizontal,\n \"share-from-square\": $fa-var-share-from-square,\n \"share-square\": $fa-var-share-square,\n \"child-combatant\": $fa-var-child-combatant,\n \"child-rifle\": $fa-var-child-rifle,\n \"gun\": $fa-var-gun,\n \"square-phone\": $fa-var-square-phone,\n \"phone-square\": $fa-var-phone-square,\n \"plus\": $fa-var-plus,\n \"add\": $fa-var-add,\n \"expand\": $fa-var-expand,\n \"computer\": $fa-var-computer,\n \"xmark\": $fa-var-xmark,\n \"close\": $fa-var-close,\n \"multiply\": $fa-var-multiply,\n \"remove\": $fa-var-remove,\n \"times\": $fa-var-times,\n \"arrows-up-down-left-right\": $fa-var-arrows-up-down-left-right,\n \"arrows\": $fa-var-arrows,\n \"chalkboard-user\": $fa-var-chalkboard-user,\n \"chalkboard-teacher\": $fa-var-chalkboard-teacher,\n \"peso-sign\": $fa-var-peso-sign,\n \"building-shield\": $fa-var-building-shield,\n \"baby\": $fa-var-baby,\n \"users-line\": $fa-var-users-line,\n \"quote-left\": $fa-var-quote-left,\n \"quote-left-alt\": $fa-var-quote-left-alt,\n \"tractor\": $fa-var-tractor,\n \"trash-arrow-up\": $fa-var-trash-arrow-up,\n \"trash-restore\": $fa-var-trash-restore,\n \"arrow-down-up-lock\": $fa-var-arrow-down-up-lock,\n \"lines-leaning\": $fa-var-lines-leaning,\n \"ruler-combined\": $fa-var-ruler-combined,\n \"copyright\": $fa-var-copyright,\n \"equals\": $fa-var-equals,\n \"blender\": $fa-var-blender,\n \"teeth\": $fa-var-teeth,\n \"shekel-sign\": $fa-var-shekel-sign,\n \"ils\": $fa-var-ils,\n \"shekel\": $fa-var-shekel,\n \"sheqel\": $fa-var-sheqel,\n \"sheqel-sign\": $fa-var-sheqel-sign,\n \"map\": $fa-var-map,\n \"rocket\": $fa-var-rocket,\n \"photo-film\": $fa-var-photo-film,\n \"photo-video\": $fa-var-photo-video,\n \"folder-minus\": $fa-var-folder-minus,\n \"hexagon-nodes-bolt\": $fa-var-hexagon-nodes-bolt,\n \"store\": $fa-var-store,\n \"arrow-trend-up\": $fa-var-arrow-trend-up,\n \"plug-circle-minus\": $fa-var-plug-circle-minus,\n \"sign-hanging\": $fa-var-sign-hanging,\n \"sign\": $fa-var-sign,\n \"bezier-curve\": $fa-var-bezier-curve,\n \"bell-slash\": $fa-var-bell-slash,\n \"tablet\": $fa-var-tablet,\n \"tablet-android\": $fa-var-tablet-android,\n \"school-flag\": $fa-var-school-flag,\n \"fill\": $fa-var-fill,\n \"angle-up\": $fa-var-angle-up,\n \"drumstick-bite\": $fa-var-drumstick-bite,\n \"holly-berry\": $fa-var-holly-berry,\n \"chevron-left\": $fa-var-chevron-left,\n \"bacteria\": $fa-var-bacteria,\n \"hand-lizard\": $fa-var-hand-lizard,\n \"notdef\": $fa-var-notdef,\n \"disease\": $fa-var-disease,\n \"briefcase-medical\": $fa-var-briefcase-medical,\n \"genderless\": $fa-var-genderless,\n \"chevron-right\": $fa-var-chevron-right,\n \"retweet\": $fa-var-retweet,\n \"car-rear\": $fa-var-car-rear,\n \"car-alt\": $fa-var-car-alt,\n \"pump-soap\": $fa-var-pump-soap,\n \"video-slash\": $fa-var-video-slash,\n \"battery-quarter\": $fa-var-battery-quarter,\n \"battery-2\": $fa-var-battery-2,\n \"radio\": $fa-var-radio,\n \"baby-carriage\": $fa-var-baby-carriage,\n \"carriage-baby\": $fa-var-carriage-baby,\n \"traffic-light\": $fa-var-traffic-light,\n \"thermometer\": $fa-var-thermometer,\n \"vr-cardboard\": $fa-var-vr-cardboard,\n \"hand-middle-finger\": $fa-var-hand-middle-finger,\n \"percent\": $fa-var-percent,\n \"percentage\": $fa-var-percentage,\n \"truck-moving\": $fa-var-truck-moving,\n \"glass-water-droplet\": $fa-var-glass-water-droplet,\n \"display\": $fa-var-display,\n \"face-smile\": $fa-var-face-smile,\n \"smile\": $fa-var-smile,\n \"thumbtack\": $fa-var-thumbtack,\n \"thumb-tack\": $fa-var-thumb-tack,\n \"trophy\": $fa-var-trophy,\n \"person-praying\": $fa-var-person-praying,\n \"pray\": $fa-var-pray,\n \"hammer\": $fa-var-hammer,\n \"hand-peace\": $fa-var-hand-peace,\n \"rotate\": $fa-var-rotate,\n \"sync-alt\": $fa-var-sync-alt,\n \"spinner\": $fa-var-spinner,\n \"robot\": $fa-var-robot,\n \"peace\": $fa-var-peace,\n \"gears\": $fa-var-gears,\n \"cogs\": $fa-var-cogs,\n \"warehouse\": $fa-var-warehouse,\n \"arrow-up-right-dots\": $fa-var-arrow-up-right-dots,\n \"splotch\": $fa-var-splotch,\n \"face-grin-hearts\": $fa-var-face-grin-hearts,\n \"grin-hearts\": $fa-var-grin-hearts,\n \"dice-four\": $fa-var-dice-four,\n \"sim-card\": $fa-var-sim-card,\n \"transgender\": $fa-var-transgender,\n \"transgender-alt\": $fa-var-transgender-alt,\n \"mercury\": $fa-var-mercury,\n \"arrow-turn-down\": $fa-var-arrow-turn-down,\n \"level-down\": $fa-var-level-down,\n \"person-falling-burst\": $fa-var-person-falling-burst,\n \"award\": $fa-var-award,\n \"ticket-simple\": $fa-var-ticket-simple,\n \"ticket-alt\": $fa-var-ticket-alt,\n \"building\": $fa-var-building,\n \"angles-left\": $fa-var-angles-left,\n \"angle-double-left\": $fa-var-angle-double-left,\n \"qrcode\": $fa-var-qrcode,\n \"clock-rotate-left\": $fa-var-clock-rotate-left,\n \"history\": $fa-var-history,\n \"face-grin-beam-sweat\": $fa-var-face-grin-beam-sweat,\n \"grin-beam-sweat\": $fa-var-grin-beam-sweat,\n \"file-export\": $fa-var-file-export,\n \"arrow-right-from-file\": $fa-var-arrow-right-from-file,\n \"shield\": $fa-var-shield,\n \"shield-blank\": $fa-var-shield-blank,\n \"arrow-up-short-wide\": $fa-var-arrow-up-short-wide,\n \"sort-amount-up-alt\": $fa-var-sort-amount-up-alt,\n \"comment-nodes\": $fa-var-comment-nodes,\n \"house-medical\": $fa-var-house-medical,\n \"golf-ball-tee\": $fa-var-golf-ball-tee,\n \"golf-ball\": $fa-var-golf-ball,\n \"circle-chevron-left\": $fa-var-circle-chevron-left,\n \"chevron-circle-left\": $fa-var-chevron-circle-left,\n \"house-chimney-window\": $fa-var-house-chimney-window,\n \"pen-nib\": $fa-var-pen-nib,\n \"tent-arrow-turn-left\": $fa-var-tent-arrow-turn-left,\n \"tents\": $fa-var-tents,\n \"wand-magic\": $fa-var-wand-magic,\n \"magic\": $fa-var-magic,\n \"dog\": $fa-var-dog,\n \"carrot\": $fa-var-carrot,\n \"moon\": $fa-var-moon,\n \"wine-glass-empty\": $fa-var-wine-glass-empty,\n \"wine-glass-alt\": $fa-var-wine-glass-alt,\n \"cheese\": $fa-var-cheese,\n \"yin-yang\": $fa-var-yin-yang,\n \"music\": $fa-var-music,\n \"code-commit\": $fa-var-code-commit,\n \"temperature-low\": $fa-var-temperature-low,\n \"person-biking\": $fa-var-person-biking,\n \"biking\": $fa-var-biking,\n \"broom\": $fa-var-broom,\n \"shield-heart\": $fa-var-shield-heart,\n \"gopuram\": $fa-var-gopuram,\n \"earth-oceania\": $fa-var-earth-oceania,\n \"globe-oceania\": $fa-var-globe-oceania,\n \"square-xmark\": $fa-var-square-xmark,\n \"times-square\": $fa-var-times-square,\n \"xmark-square\": $fa-var-xmark-square,\n \"hashtag\": $fa-var-hashtag,\n \"up-right-and-down-left-from-center\": $fa-var-up-right-and-down-left-from-center,\n \"expand-alt\": $fa-var-expand-alt,\n \"oil-can\": $fa-var-oil-can,\n \"t\": $fa-var-t,\n \"hippo\": $fa-var-hippo,\n \"chart-column\": $fa-var-chart-column,\n \"infinity\": $fa-var-infinity,\n \"vial-circle-check\": $fa-var-vial-circle-check,\n \"person-arrow-down-to-line\": $fa-var-person-arrow-down-to-line,\n \"voicemail\": $fa-var-voicemail,\n \"fan\": $fa-var-fan,\n \"person-walking-luggage\": $fa-var-person-walking-luggage,\n \"up-down\": $fa-var-up-down,\n \"arrows-alt-v\": $fa-var-arrows-alt-v,\n \"cloud-moon-rain\": $fa-var-cloud-moon-rain,\n \"calendar\": $fa-var-calendar,\n \"trailer\": $fa-var-trailer,\n \"bahai\": $fa-var-bahai,\n \"haykal\": $fa-var-haykal,\n \"sd-card\": $fa-var-sd-card,\n \"dragon\": $fa-var-dragon,\n \"shoe-prints\": $fa-var-shoe-prints,\n \"circle-plus\": $fa-var-circle-plus,\n \"plus-circle\": $fa-var-plus-circle,\n \"face-grin-tongue-wink\": $fa-var-face-grin-tongue-wink,\n \"grin-tongue-wink\": $fa-var-grin-tongue-wink,\n \"hand-holding\": $fa-var-hand-holding,\n \"plug-circle-exclamation\": $fa-var-plug-circle-exclamation,\n \"link-slash\": $fa-var-link-slash,\n \"chain-broken\": $fa-var-chain-broken,\n \"chain-slash\": $fa-var-chain-slash,\n \"unlink\": $fa-var-unlink,\n \"clone\": $fa-var-clone,\n \"person-walking-arrow-loop-left\": $fa-var-person-walking-arrow-loop-left,\n \"arrow-up-z-a\": $fa-var-arrow-up-z-a,\n \"sort-alpha-up-alt\": $fa-var-sort-alpha-up-alt,\n \"fire-flame-curved\": $fa-var-fire-flame-curved,\n \"fire-alt\": $fa-var-fire-alt,\n \"tornado\": $fa-var-tornado,\n \"file-circle-plus\": $fa-var-file-circle-plus,\n \"book-quran\": $fa-var-book-quran,\n \"quran\": $fa-var-quran,\n \"anchor\": $fa-var-anchor,\n \"border-all\": $fa-var-border-all,\n \"face-angry\": $fa-var-face-angry,\n \"angry\": $fa-var-angry,\n \"cookie-bite\": $fa-var-cookie-bite,\n \"arrow-trend-down\": $fa-var-arrow-trend-down,\n \"rss\": $fa-var-rss,\n \"feed\": $fa-var-feed,\n \"draw-polygon\": $fa-var-draw-polygon,\n \"scale-balanced\": $fa-var-scale-balanced,\n \"balance-scale\": $fa-var-balance-scale,\n \"gauge-simple-high\": $fa-var-gauge-simple-high,\n \"tachometer\": $fa-var-tachometer,\n \"tachometer-fast\": $fa-var-tachometer-fast,\n \"shower\": $fa-var-shower,\n \"desktop\": $fa-var-desktop,\n \"desktop-alt\": $fa-var-desktop-alt,\n \"m\": $fa-var-m,\n \"table-list\": $fa-var-table-list,\n \"th-list\": $fa-var-th-list,\n \"comment-sms\": $fa-var-comment-sms,\n \"sms\": $fa-var-sms,\n \"book\": $fa-var-book,\n \"user-plus\": $fa-var-user-plus,\n \"check\": $fa-var-check,\n \"battery-three-quarters\": $fa-var-battery-three-quarters,\n \"battery-4\": $fa-var-battery-4,\n \"house-circle-check\": $fa-var-house-circle-check,\n \"angle-left\": $fa-var-angle-left,\n \"diagram-successor\": $fa-var-diagram-successor,\n \"truck-arrow-right\": $fa-var-truck-arrow-right,\n \"arrows-split-up-and-left\": $fa-var-arrows-split-up-and-left,\n \"hand-fist\": $fa-var-hand-fist,\n \"fist-raised\": $fa-var-fist-raised,\n \"cloud-moon\": $fa-var-cloud-moon,\n \"briefcase\": $fa-var-briefcase,\n \"person-falling\": $fa-var-person-falling,\n \"image-portrait\": $fa-var-image-portrait,\n \"portrait\": $fa-var-portrait,\n \"user-tag\": $fa-var-user-tag,\n \"rug\": $fa-var-rug,\n \"earth-europe\": $fa-var-earth-europe,\n \"globe-europe\": $fa-var-globe-europe,\n \"cart-flatbed-suitcase\": $fa-var-cart-flatbed-suitcase,\n \"luggage-cart\": $fa-var-luggage-cart,\n \"rectangle-xmark\": $fa-var-rectangle-xmark,\n \"rectangle-times\": $fa-var-rectangle-times,\n \"times-rectangle\": $fa-var-times-rectangle,\n \"window-close\": $fa-var-window-close,\n \"baht-sign\": $fa-var-baht-sign,\n \"book-open\": $fa-var-book-open,\n \"book-journal-whills\": $fa-var-book-journal-whills,\n \"journal-whills\": $fa-var-journal-whills,\n \"handcuffs\": $fa-var-handcuffs,\n \"triangle-exclamation\": $fa-var-triangle-exclamation,\n \"exclamation-triangle\": $fa-var-exclamation-triangle,\n \"warning\": $fa-var-warning,\n \"database\": $fa-var-database,\n \"share\": $fa-var-share,\n \"mail-forward\": $fa-var-mail-forward,\n \"bottle-droplet\": $fa-var-bottle-droplet,\n \"mask-face\": $fa-var-mask-face,\n \"hill-rockslide\": $fa-var-hill-rockslide,\n \"right-left\": $fa-var-right-left,\n \"exchange-alt\": $fa-var-exchange-alt,\n \"paper-plane\": $fa-var-paper-plane,\n \"road-circle-exclamation\": $fa-var-road-circle-exclamation,\n \"dungeon\": $fa-var-dungeon,\n \"align-right\": $fa-var-align-right,\n \"money-bill-1-wave\": $fa-var-money-bill-1-wave,\n \"money-bill-wave-alt\": $fa-var-money-bill-wave-alt,\n \"life-ring\": $fa-var-life-ring,\n \"hands\": $fa-var-hands,\n \"sign-language\": $fa-var-sign-language,\n \"signing\": $fa-var-signing,\n \"calendar-day\": $fa-var-calendar-day,\n \"water-ladder\": $fa-var-water-ladder,\n \"ladder-water\": $fa-var-ladder-water,\n \"swimming-pool\": $fa-var-swimming-pool,\n \"arrows-up-down\": $fa-var-arrows-up-down,\n \"arrows-v\": $fa-var-arrows-v,\n \"face-grimace\": $fa-var-face-grimace,\n \"grimace\": $fa-var-grimace,\n \"wheelchair-move\": $fa-var-wheelchair-move,\n \"wheelchair-alt\": $fa-var-wheelchair-alt,\n \"turn-down\": $fa-var-turn-down,\n \"level-down-alt\": $fa-var-level-down-alt,\n \"person-walking-arrow-right\": $fa-var-person-walking-arrow-right,\n \"square-envelope\": $fa-var-square-envelope,\n \"envelope-square\": $fa-var-envelope-square,\n \"dice\": $fa-var-dice,\n \"bowling-ball\": $fa-var-bowling-ball,\n \"brain\": $fa-var-brain,\n \"bandage\": $fa-var-bandage,\n \"band-aid\": $fa-var-band-aid,\n \"calendar-minus\": $fa-var-calendar-minus,\n \"circle-xmark\": $fa-var-circle-xmark,\n \"times-circle\": $fa-var-times-circle,\n \"xmark-circle\": $fa-var-xmark-circle,\n \"gifts\": $fa-var-gifts,\n \"hotel\": $fa-var-hotel,\n \"earth-asia\": $fa-var-earth-asia,\n \"globe-asia\": $fa-var-globe-asia,\n \"id-card-clip\": $fa-var-id-card-clip,\n \"id-card-alt\": $fa-var-id-card-alt,\n \"magnifying-glass-plus\": $fa-var-magnifying-glass-plus,\n \"search-plus\": $fa-var-search-plus,\n \"thumbs-up\": $fa-var-thumbs-up,\n \"user-clock\": $fa-var-user-clock,\n \"hand-dots\": $fa-var-hand-dots,\n \"allergies\": $fa-var-allergies,\n \"file-invoice\": $fa-var-file-invoice,\n \"window-minimize\": $fa-var-window-minimize,\n \"mug-saucer\": $fa-var-mug-saucer,\n \"coffee\": $fa-var-coffee,\n \"brush\": $fa-var-brush,\n \"file-half-dashed\": $fa-var-file-half-dashed,\n \"mask\": $fa-var-mask,\n \"magnifying-glass-minus\": $fa-var-magnifying-glass-minus,\n \"search-minus\": $fa-var-search-minus,\n \"ruler-vertical\": $fa-var-ruler-vertical,\n \"user-large\": $fa-var-user-large,\n \"user-alt\": $fa-var-user-alt,\n \"train-tram\": $fa-var-train-tram,\n \"user-nurse\": $fa-var-user-nurse,\n \"syringe\": $fa-var-syringe,\n \"cloud-sun\": $fa-var-cloud-sun,\n \"stopwatch-20\": $fa-var-stopwatch-20,\n \"square-full\": $fa-var-square-full,\n \"magnet\": $fa-var-magnet,\n \"jar\": $fa-var-jar,\n \"note-sticky\": $fa-var-note-sticky,\n \"sticky-note\": $fa-var-sticky-note,\n \"bug-slash\": $fa-var-bug-slash,\n \"arrow-up-from-water-pump\": $fa-var-arrow-up-from-water-pump,\n \"bone\": $fa-var-bone,\n \"table-cells-row-unlock\": $fa-var-table-cells-row-unlock,\n \"user-injured\": $fa-var-user-injured,\n \"face-sad-tear\": $fa-var-face-sad-tear,\n \"sad-tear\": $fa-var-sad-tear,\n \"plane\": $fa-var-plane,\n \"tent-arrows-down\": $fa-var-tent-arrows-down,\n \"exclamation\": $fa-var-exclamation,\n \"arrows-spin\": $fa-var-arrows-spin,\n \"print\": $fa-var-print,\n \"turkish-lira-sign\": $fa-var-turkish-lira-sign,\n \"try\": $fa-var-try,\n \"turkish-lira\": $fa-var-turkish-lira,\n \"dollar-sign\": $fa-var-dollar-sign,\n \"dollar\": $fa-var-dollar,\n \"usd\": $fa-var-usd,\n \"x\": $fa-var-x,\n \"magnifying-glass-dollar\": $fa-var-magnifying-glass-dollar,\n \"search-dollar\": $fa-var-search-dollar,\n \"users-gear\": $fa-var-users-gear,\n \"users-cog\": $fa-var-users-cog,\n \"person-military-pointing\": $fa-var-person-military-pointing,\n \"building-columns\": $fa-var-building-columns,\n \"bank\": $fa-var-bank,\n \"institution\": $fa-var-institution,\n \"museum\": $fa-var-museum,\n \"university\": $fa-var-university,\n \"umbrella\": $fa-var-umbrella,\n \"trowel\": $fa-var-trowel,\n \"d\": $fa-var-d,\n \"stapler\": $fa-var-stapler,\n \"masks-theater\": $fa-var-masks-theater,\n \"theater-masks\": $fa-var-theater-masks,\n \"kip-sign\": $fa-var-kip-sign,\n \"hand-point-left\": $fa-var-hand-point-left,\n \"handshake-simple\": $fa-var-handshake-simple,\n \"handshake-alt\": $fa-var-handshake-alt,\n \"jet-fighter\": $fa-var-jet-fighter,\n \"fighter-jet\": $fa-var-fighter-jet,\n \"square-share-nodes\": $fa-var-square-share-nodes,\n \"share-alt-square\": $fa-var-share-alt-square,\n \"barcode\": $fa-var-barcode,\n \"plus-minus\": $fa-var-plus-minus,\n \"video\": $fa-var-video,\n \"video-camera\": $fa-var-video-camera,\n \"graduation-cap\": $fa-var-graduation-cap,\n \"mortar-board\": $fa-var-mortar-board,\n \"hand-holding-medical\": $fa-var-hand-holding-medical,\n \"person-circle-check\": $fa-var-person-circle-check,\n \"turn-up\": $fa-var-turn-up,\n \"level-up-alt\": $fa-var-level-up-alt,\n);\n\n$fa-brand-icons: (\n \"monero\": $fa-var-monero,\n \"hooli\": $fa-var-hooli,\n \"yelp\": $fa-var-yelp,\n \"cc-visa\": $fa-var-cc-visa,\n \"lastfm\": $fa-var-lastfm,\n \"shopware\": $fa-var-shopware,\n \"creative-commons-nc\": $fa-var-creative-commons-nc,\n \"aws\": $fa-var-aws,\n \"redhat\": $fa-var-redhat,\n \"yoast\": $fa-var-yoast,\n \"cloudflare\": $fa-var-cloudflare,\n \"ups\": $fa-var-ups,\n \"pixiv\": $fa-var-pixiv,\n \"wpexplorer\": $fa-var-wpexplorer,\n \"dyalog\": $fa-var-dyalog,\n \"bity\": $fa-var-bity,\n \"stackpath\": $fa-var-stackpath,\n \"buysellads\": $fa-var-buysellads,\n \"first-order\": $fa-var-first-order,\n \"modx\": $fa-var-modx,\n \"guilded\": $fa-var-guilded,\n \"vnv\": $fa-var-vnv,\n \"square-js\": $fa-var-square-js,\n \"js-square\": $fa-var-js-square,\n \"microsoft\": $fa-var-microsoft,\n \"qq\": $fa-var-qq,\n \"orcid\": $fa-var-orcid,\n \"java\": $fa-var-java,\n \"invision\": $fa-var-invision,\n \"creative-commons-pd-alt\": $fa-var-creative-commons-pd-alt,\n \"centercode\": $fa-var-centercode,\n \"glide-g\": $fa-var-glide-g,\n \"drupal\": $fa-var-drupal,\n \"jxl\": $fa-var-jxl,\n \"dart-lang\": $fa-var-dart-lang,\n \"hire-a-helper\": $fa-var-hire-a-helper,\n \"creative-commons-by\": $fa-var-creative-commons-by,\n \"unity\": $fa-var-unity,\n \"whmcs\": $fa-var-whmcs,\n \"rocketchat\": $fa-var-rocketchat,\n \"vk\": $fa-var-vk,\n \"untappd\": $fa-var-untappd,\n \"mailchimp\": $fa-var-mailchimp,\n \"css3-alt\": $fa-var-css3-alt,\n \"square-reddit\": $fa-var-square-reddit,\n \"reddit-square\": $fa-var-reddit-square,\n \"vimeo-v\": $fa-var-vimeo-v,\n \"contao\": $fa-var-contao,\n \"square-font-awesome\": $fa-var-square-font-awesome,\n \"deskpro\": $fa-var-deskpro,\n \"brave\": $fa-var-brave,\n \"sistrix\": $fa-var-sistrix,\n \"square-instagram\": $fa-var-square-instagram,\n \"instagram-square\": $fa-var-instagram-square,\n \"battle-net\": $fa-var-battle-net,\n \"the-red-yeti\": $fa-var-the-red-yeti,\n \"square-hacker-news\": $fa-var-square-hacker-news,\n \"hacker-news-square\": $fa-var-hacker-news-square,\n \"edge\": $fa-var-edge,\n \"threads\": $fa-var-threads,\n \"napster\": $fa-var-napster,\n \"square-snapchat\": $fa-var-square-snapchat,\n \"snapchat-square\": $fa-var-snapchat-square,\n \"google-plus-g\": $fa-var-google-plus-g,\n \"artstation\": $fa-var-artstation,\n \"markdown\": $fa-var-markdown,\n \"sourcetree\": $fa-var-sourcetree,\n \"google-plus\": $fa-var-google-plus,\n \"diaspora\": $fa-var-diaspora,\n \"foursquare\": $fa-var-foursquare,\n \"stack-overflow\": $fa-var-stack-overflow,\n \"github-alt\": $fa-var-github-alt,\n \"phoenix-squadron\": $fa-var-phoenix-squadron,\n \"pagelines\": $fa-var-pagelines,\n \"algolia\": $fa-var-algolia,\n \"red-river\": $fa-var-red-river,\n \"creative-commons-sa\": $fa-var-creative-commons-sa,\n \"safari\": $fa-var-safari,\n \"google\": $fa-var-google,\n \"square-font-awesome-stroke\": $fa-var-square-font-awesome-stroke,\n \"font-awesome-alt\": $fa-var-font-awesome-alt,\n \"atlassian\": $fa-var-atlassian,\n \"linkedin-in\": $fa-var-linkedin-in,\n \"digital-ocean\": $fa-var-digital-ocean,\n \"nimblr\": $fa-var-nimblr,\n \"chromecast\": $fa-var-chromecast,\n \"evernote\": $fa-var-evernote,\n \"hacker-news\": $fa-var-hacker-news,\n \"creative-commons-sampling\": $fa-var-creative-commons-sampling,\n \"adversal\": $fa-var-adversal,\n \"creative-commons\": $fa-var-creative-commons,\n \"watchman-monitoring\": $fa-var-watchman-monitoring,\n \"fonticons\": $fa-var-fonticons,\n \"weixin\": $fa-var-weixin,\n \"shirtsinbulk\": $fa-var-shirtsinbulk,\n \"codepen\": $fa-var-codepen,\n \"git-alt\": $fa-var-git-alt,\n \"lyft\": $fa-var-lyft,\n \"rev\": $fa-var-rev,\n \"windows\": $fa-var-windows,\n \"wizards-of-the-coast\": $fa-var-wizards-of-the-coast,\n \"square-viadeo\": $fa-var-square-viadeo,\n \"viadeo-square\": $fa-var-viadeo-square,\n \"meetup\": $fa-var-meetup,\n \"centos\": $fa-var-centos,\n \"adn\": $fa-var-adn,\n \"cloudsmith\": $fa-var-cloudsmith,\n \"opensuse\": $fa-var-opensuse,\n \"pied-piper-alt\": $fa-var-pied-piper-alt,\n \"square-dribbble\": $fa-var-square-dribbble,\n \"dribbble-square\": $fa-var-dribbble-square,\n \"codiepie\": $fa-var-codiepie,\n \"node\": $fa-var-node,\n \"mix\": $fa-var-mix,\n \"steam\": $fa-var-steam,\n \"cc-apple-pay\": $fa-var-cc-apple-pay,\n \"scribd\": $fa-var-scribd,\n \"debian\": $fa-var-debian,\n \"openid\": $fa-var-openid,\n \"instalod\": $fa-var-instalod,\n \"files-pinwheel\": $fa-var-files-pinwheel,\n \"expeditedssl\": $fa-var-expeditedssl,\n \"sellcast\": $fa-var-sellcast,\n \"square-twitter\": $fa-var-square-twitter,\n \"twitter-square\": $fa-var-twitter-square,\n \"r-project\": $fa-var-r-project,\n \"delicious\": $fa-var-delicious,\n \"freebsd\": $fa-var-freebsd,\n \"vuejs\": $fa-var-vuejs,\n \"accusoft\": $fa-var-accusoft,\n \"ioxhost\": $fa-var-ioxhost,\n \"fonticons-fi\": $fa-var-fonticons-fi,\n \"app-store\": $fa-var-app-store,\n \"cc-mastercard\": $fa-var-cc-mastercard,\n \"itunes-note\": $fa-var-itunes-note,\n \"golang\": $fa-var-golang,\n \"kickstarter\": $fa-var-kickstarter,\n \"square-kickstarter\": $fa-var-square-kickstarter,\n \"grav\": $fa-var-grav,\n \"weibo\": $fa-var-weibo,\n \"uncharted\": $fa-var-uncharted,\n \"firstdraft\": $fa-var-firstdraft,\n \"square-youtube\": $fa-var-square-youtube,\n \"youtube-square\": $fa-var-youtube-square,\n \"wikipedia-w\": $fa-var-wikipedia-w,\n \"wpressr\": $fa-var-wpressr,\n \"rendact\": $fa-var-rendact,\n \"angellist\": $fa-var-angellist,\n \"galactic-republic\": $fa-var-galactic-republic,\n \"nfc-directional\": $fa-var-nfc-directional,\n \"skype\": $fa-var-skype,\n \"joget\": $fa-var-joget,\n \"fedora\": $fa-var-fedora,\n \"stripe-s\": $fa-var-stripe-s,\n \"meta\": $fa-var-meta,\n \"laravel\": $fa-var-laravel,\n \"hotjar\": $fa-var-hotjar,\n \"bluetooth-b\": $fa-var-bluetooth-b,\n \"square-letterboxd\": $fa-var-square-letterboxd,\n \"sticker-mule\": $fa-var-sticker-mule,\n \"creative-commons-zero\": $fa-var-creative-commons-zero,\n \"hips\": $fa-var-hips,\n \"css\": $fa-var-css,\n \"behance\": $fa-var-behance,\n \"reddit\": $fa-var-reddit,\n \"discord\": $fa-var-discord,\n \"chrome\": $fa-var-chrome,\n \"app-store-ios\": $fa-var-app-store-ios,\n \"cc-discover\": $fa-var-cc-discover,\n \"wpbeginner\": $fa-var-wpbeginner,\n \"confluence\": $fa-var-confluence,\n \"shoelace\": $fa-var-shoelace,\n \"mdb\": $fa-var-mdb,\n \"dochub\": $fa-var-dochub,\n \"accessible-icon\": $fa-var-accessible-icon,\n \"ebay\": $fa-var-ebay,\n \"amazon\": $fa-var-amazon,\n \"unsplash\": $fa-var-unsplash,\n \"yarn\": $fa-var-yarn,\n \"square-steam\": $fa-var-square-steam,\n \"steam-square\": $fa-var-steam-square,\n \"500px\": $fa-var-500px,\n \"square-vimeo\": $fa-var-square-vimeo,\n \"vimeo-square\": $fa-var-vimeo-square,\n \"asymmetrik\": $fa-var-asymmetrik,\n \"font-awesome\": $fa-var-font-awesome,\n \"font-awesome-flag\": $fa-var-font-awesome-flag,\n \"font-awesome-logo-full\": $fa-var-font-awesome-logo-full,\n \"gratipay\": $fa-var-gratipay,\n \"apple\": $fa-var-apple,\n \"hive\": $fa-var-hive,\n \"gitkraken\": $fa-var-gitkraken,\n \"keybase\": $fa-var-keybase,\n \"apple-pay\": $fa-var-apple-pay,\n \"padlet\": $fa-var-padlet,\n \"amazon-pay\": $fa-var-amazon-pay,\n \"square-github\": $fa-var-square-github,\n \"github-square\": $fa-var-github-square,\n \"stumbleupon\": $fa-var-stumbleupon,\n \"fedex\": $fa-var-fedex,\n \"phoenix-framework\": $fa-var-phoenix-framework,\n \"shopify\": $fa-var-shopify,\n \"neos\": $fa-var-neos,\n \"square-threads\": $fa-var-square-threads,\n \"hackerrank\": $fa-var-hackerrank,\n \"researchgate\": $fa-var-researchgate,\n \"swift\": $fa-var-swift,\n \"angular\": $fa-var-angular,\n \"speakap\": $fa-var-speakap,\n \"angrycreative\": $fa-var-angrycreative,\n \"y-combinator\": $fa-var-y-combinator,\n \"empire\": $fa-var-empire,\n \"envira\": $fa-var-envira,\n \"google-scholar\": $fa-var-google-scholar,\n \"square-gitlab\": $fa-var-square-gitlab,\n \"gitlab-square\": $fa-var-gitlab-square,\n \"studiovinari\": $fa-var-studiovinari,\n \"pied-piper\": $fa-var-pied-piper,\n \"wordpress\": $fa-var-wordpress,\n \"product-hunt\": $fa-var-product-hunt,\n \"firefox\": $fa-var-firefox,\n \"linode\": $fa-var-linode,\n \"goodreads\": $fa-var-goodreads,\n \"square-odnoklassniki\": $fa-var-square-odnoklassniki,\n \"odnoklassniki-square\": $fa-var-odnoklassniki-square,\n \"jsfiddle\": $fa-var-jsfiddle,\n \"sith\": $fa-var-sith,\n \"themeisle\": $fa-var-themeisle,\n \"page4\": $fa-var-page4,\n \"hashnode\": $fa-var-hashnode,\n \"react\": $fa-var-react,\n \"cc-paypal\": $fa-var-cc-paypal,\n \"squarespace\": $fa-var-squarespace,\n \"cc-stripe\": $fa-var-cc-stripe,\n \"creative-commons-share\": $fa-var-creative-commons-share,\n \"bitcoin\": $fa-var-bitcoin,\n \"keycdn\": $fa-var-keycdn,\n \"opera\": $fa-var-opera,\n \"itch-io\": $fa-var-itch-io,\n \"umbraco\": $fa-var-umbraco,\n \"galactic-senate\": $fa-var-galactic-senate,\n \"ubuntu\": $fa-var-ubuntu,\n \"draft2digital\": $fa-var-draft2digital,\n \"stripe\": $fa-var-stripe,\n \"houzz\": $fa-var-houzz,\n \"gg\": $fa-var-gg,\n \"dhl\": $fa-var-dhl,\n \"square-pinterest\": $fa-var-square-pinterest,\n \"pinterest-square\": $fa-var-pinterest-square,\n \"xing\": $fa-var-xing,\n \"blackberry\": $fa-var-blackberry,\n \"creative-commons-pd\": $fa-var-creative-commons-pd,\n \"playstation\": $fa-var-playstation,\n \"quinscape\": $fa-var-quinscape,\n \"less\": $fa-var-less,\n \"blogger-b\": $fa-var-blogger-b,\n \"opencart\": $fa-var-opencart,\n \"vine\": $fa-var-vine,\n \"signal-messenger\": $fa-var-signal-messenger,\n \"paypal\": $fa-var-paypal,\n \"gitlab\": $fa-var-gitlab,\n \"typo3\": $fa-var-typo3,\n \"reddit-alien\": $fa-var-reddit-alien,\n \"yahoo\": $fa-var-yahoo,\n \"dailymotion\": $fa-var-dailymotion,\n \"affiliatetheme\": $fa-var-affiliatetheme,\n \"pied-piper-pp\": $fa-var-pied-piper-pp,\n \"bootstrap\": $fa-var-bootstrap,\n \"odnoklassniki\": $fa-var-odnoklassniki,\n \"nfc-symbol\": $fa-var-nfc-symbol,\n \"mintbit\": $fa-var-mintbit,\n \"ethereum\": $fa-var-ethereum,\n \"speaker-deck\": $fa-var-speaker-deck,\n \"creative-commons-nc-eu\": $fa-var-creative-commons-nc-eu,\n \"patreon\": $fa-var-patreon,\n \"avianex\": $fa-var-avianex,\n \"ello\": $fa-var-ello,\n \"gofore\": $fa-var-gofore,\n \"bimobject\": $fa-var-bimobject,\n \"brave-reverse\": $fa-var-brave-reverse,\n \"facebook-f\": $fa-var-facebook-f,\n \"square-google-plus\": $fa-var-square-google-plus,\n \"google-plus-square\": $fa-var-google-plus-square,\n \"web-awesome\": $fa-var-web-awesome,\n \"mandalorian\": $fa-var-mandalorian,\n \"first-order-alt\": $fa-var-first-order-alt,\n \"osi\": $fa-var-osi,\n \"google-wallet\": $fa-var-google-wallet,\n \"d-and-d-beyond\": $fa-var-d-and-d-beyond,\n \"periscope\": $fa-var-periscope,\n \"fulcrum\": $fa-var-fulcrum,\n \"cloudscale\": $fa-var-cloudscale,\n \"forumbee\": $fa-var-forumbee,\n \"mizuni\": $fa-var-mizuni,\n \"schlix\": $fa-var-schlix,\n \"square-xing\": $fa-var-square-xing,\n \"xing-square\": $fa-var-xing-square,\n \"bandcamp\": $fa-var-bandcamp,\n \"wpforms\": $fa-var-wpforms,\n \"cloudversify\": $fa-var-cloudversify,\n \"usps\": $fa-var-usps,\n \"megaport\": $fa-var-megaport,\n \"magento\": $fa-var-magento,\n \"spotify\": $fa-var-spotify,\n \"optin-monster\": $fa-var-optin-monster,\n \"fly\": $fa-var-fly,\n \"square-bluesky\": $fa-var-square-bluesky,\n \"aviato\": $fa-var-aviato,\n \"itunes\": $fa-var-itunes,\n \"cuttlefish\": $fa-var-cuttlefish,\n \"blogger\": $fa-var-blogger,\n \"flickr\": $fa-var-flickr,\n \"viber\": $fa-var-viber,\n \"soundcloud\": $fa-var-soundcloud,\n \"digg\": $fa-var-digg,\n \"tencent-weibo\": $fa-var-tencent-weibo,\n \"letterboxd\": $fa-var-letterboxd,\n \"symfony\": $fa-var-symfony,\n \"maxcdn\": $fa-var-maxcdn,\n \"etsy\": $fa-var-etsy,\n \"facebook-messenger\": $fa-var-facebook-messenger,\n \"audible\": $fa-var-audible,\n \"think-peaks\": $fa-var-think-peaks,\n \"bilibili\": $fa-var-bilibili,\n \"erlang\": $fa-var-erlang,\n \"x-twitter\": $fa-var-x-twitter,\n \"cotton-bureau\": $fa-var-cotton-bureau,\n \"dashcube\": $fa-var-dashcube,\n \"42-group\": $fa-var-42-group,\n \"innosoft\": $fa-var-innosoft,\n \"stack-exchange\": $fa-var-stack-exchange,\n \"elementor\": $fa-var-elementor,\n \"square-pied-piper\": $fa-var-square-pied-piper,\n \"pied-piper-square\": $fa-var-pied-piper-square,\n \"creative-commons-nd\": $fa-var-creative-commons-nd,\n \"palfed\": $fa-var-palfed,\n \"superpowers\": $fa-var-superpowers,\n \"resolving\": $fa-var-resolving,\n \"xbox\": $fa-var-xbox,\n \"square-web-awesome-stroke\": $fa-var-square-web-awesome-stroke,\n \"searchengin\": $fa-var-searchengin,\n \"tiktok\": $fa-var-tiktok,\n \"square-facebook\": $fa-var-square-facebook,\n \"facebook-square\": $fa-var-facebook-square,\n \"renren\": $fa-var-renren,\n \"linux\": $fa-var-linux,\n \"glide\": $fa-var-glide,\n \"linkedin\": $fa-var-linkedin,\n \"hubspot\": $fa-var-hubspot,\n \"deploydog\": $fa-var-deploydog,\n \"twitch\": $fa-var-twitch,\n \"flutter\": $fa-var-flutter,\n \"ravelry\": $fa-var-ravelry,\n \"mixer\": $fa-var-mixer,\n \"square-lastfm\": $fa-var-square-lastfm,\n \"lastfm-square\": $fa-var-lastfm-square,\n \"vimeo\": $fa-var-vimeo,\n \"mendeley\": $fa-var-mendeley,\n \"uniregistry\": $fa-var-uniregistry,\n \"figma\": $fa-var-figma,\n \"creative-commons-remix\": $fa-var-creative-commons-remix,\n \"cc-amazon-pay\": $fa-var-cc-amazon-pay,\n \"dropbox\": $fa-var-dropbox,\n \"instagram\": $fa-var-instagram,\n \"cmplid\": $fa-var-cmplid,\n \"upwork\": $fa-var-upwork,\n \"facebook\": $fa-var-facebook,\n \"gripfire\": $fa-var-gripfire,\n \"jedi-order\": $fa-var-jedi-order,\n \"uikit\": $fa-var-uikit,\n \"fort-awesome-alt\": $fa-var-fort-awesome-alt,\n \"phabricator\": $fa-var-phabricator,\n \"ussunnah\": $fa-var-ussunnah,\n \"earlybirds\": $fa-var-earlybirds,\n \"trade-federation\": $fa-var-trade-federation,\n \"autoprefixer\": $fa-var-autoprefixer,\n \"whatsapp\": $fa-var-whatsapp,\n \"square-upwork\": $fa-var-square-upwork,\n \"slideshare\": $fa-var-slideshare,\n \"google-play\": $fa-var-google-play,\n \"viadeo\": $fa-var-viadeo,\n \"line\": $fa-var-line,\n \"google-drive\": $fa-var-google-drive,\n \"servicestack\": $fa-var-servicestack,\n \"simplybuilt\": $fa-var-simplybuilt,\n \"bitbucket\": $fa-var-bitbucket,\n \"imdb\": $fa-var-imdb,\n \"deezer\": $fa-var-deezer,\n \"raspberry-pi\": $fa-var-raspberry-pi,\n \"jira\": $fa-var-jira,\n \"docker\": $fa-var-docker,\n \"screenpal\": $fa-var-screenpal,\n \"bluetooth\": $fa-var-bluetooth,\n \"gitter\": $fa-var-gitter,\n \"d-and-d\": $fa-var-d-and-d,\n \"microblog\": $fa-var-microblog,\n \"cc-diners-club\": $fa-var-cc-diners-club,\n \"gg-circle\": $fa-var-gg-circle,\n \"pied-piper-hat\": $fa-var-pied-piper-hat,\n \"kickstarter-k\": $fa-var-kickstarter-k,\n \"yandex\": $fa-var-yandex,\n \"readme\": $fa-var-readme,\n \"html5\": $fa-var-html5,\n \"sellsy\": $fa-var-sellsy,\n \"square-web-awesome\": $fa-var-square-web-awesome,\n \"sass\": $fa-var-sass,\n \"wirsindhandwerk\": $fa-var-wirsindhandwerk,\n \"wsh\": $fa-var-wsh,\n \"buromobelexperte\": $fa-var-buromobelexperte,\n \"salesforce\": $fa-var-salesforce,\n \"octopus-deploy\": $fa-var-octopus-deploy,\n \"medapps\": $fa-var-medapps,\n \"ns8\": $fa-var-ns8,\n \"pinterest-p\": $fa-var-pinterest-p,\n \"apper\": $fa-var-apper,\n \"fort-awesome\": $fa-var-fort-awesome,\n \"waze\": $fa-var-waze,\n \"bluesky\": $fa-var-bluesky,\n \"cc-jcb\": $fa-var-cc-jcb,\n \"snapchat\": $fa-var-snapchat,\n \"snapchat-ghost\": $fa-var-snapchat-ghost,\n \"fantasy-flight-games\": $fa-var-fantasy-flight-games,\n \"rust\": $fa-var-rust,\n \"wix\": $fa-var-wix,\n \"square-behance\": $fa-var-square-behance,\n \"behance-square\": $fa-var-behance-square,\n \"supple\": $fa-var-supple,\n \"webflow\": $fa-var-webflow,\n \"rebel\": $fa-var-rebel,\n \"css3\": $fa-var-css3,\n \"staylinked\": $fa-var-staylinked,\n \"kaggle\": $fa-var-kaggle,\n \"space-awesome\": $fa-var-space-awesome,\n \"deviantart\": $fa-var-deviantart,\n \"cpanel\": $fa-var-cpanel,\n \"goodreads-g\": $fa-var-goodreads-g,\n \"square-git\": $fa-var-square-git,\n \"git-square\": $fa-var-git-square,\n \"square-tumblr\": $fa-var-square-tumblr,\n \"tumblr-square\": $fa-var-tumblr-square,\n \"trello\": $fa-var-trello,\n \"creative-commons-nc-jp\": $fa-var-creative-commons-nc-jp,\n \"get-pocket\": $fa-var-get-pocket,\n \"perbyte\": $fa-var-perbyte,\n \"grunt\": $fa-var-grunt,\n \"weebly\": $fa-var-weebly,\n \"connectdevelop\": $fa-var-connectdevelop,\n \"leanpub\": $fa-var-leanpub,\n \"black-tie\": $fa-var-black-tie,\n \"themeco\": $fa-var-themeco,\n \"python\": $fa-var-python,\n \"android\": $fa-var-android,\n \"bots\": $fa-var-bots,\n \"free-code-camp\": $fa-var-free-code-camp,\n \"hornbill\": $fa-var-hornbill,\n \"js\": $fa-var-js,\n \"ideal\": $fa-var-ideal,\n \"git\": $fa-var-git,\n \"dev\": $fa-var-dev,\n \"sketch\": $fa-var-sketch,\n \"yandex-international\": $fa-var-yandex-international,\n \"cc-amex\": $fa-var-cc-amex,\n \"uber\": $fa-var-uber,\n \"github\": $fa-var-github,\n \"php\": $fa-var-php,\n \"alipay\": $fa-var-alipay,\n \"youtube\": $fa-var-youtube,\n \"skyatlas\": $fa-var-skyatlas,\n \"firefox-browser\": $fa-var-firefox-browser,\n \"replyd\": $fa-var-replyd,\n \"suse\": $fa-var-suse,\n \"jenkins\": $fa-var-jenkins,\n \"twitter\": $fa-var-twitter,\n \"rockrms\": $fa-var-rockrms,\n \"pinterest\": $fa-var-pinterest,\n \"buffer\": $fa-var-buffer,\n \"npm\": $fa-var-npm,\n \"yammer\": $fa-var-yammer,\n \"btc\": $fa-var-btc,\n \"dribbble\": $fa-var-dribbble,\n \"stumbleupon-circle\": $fa-var-stumbleupon-circle,\n \"internet-explorer\": $fa-var-internet-explorer,\n \"stubber\": $fa-var-stubber,\n \"telegram\": $fa-var-telegram,\n \"telegram-plane\": $fa-var-telegram-plane,\n \"old-republic\": $fa-var-old-republic,\n \"odysee\": $fa-var-odysee,\n \"square-whatsapp\": $fa-var-square-whatsapp,\n \"whatsapp-square\": $fa-var-whatsapp-square,\n \"node-js\": $fa-var-node-js,\n \"edge-legacy\": $fa-var-edge-legacy,\n \"slack\": $fa-var-slack,\n \"slack-hash\": $fa-var-slack-hash,\n \"medrt\": $fa-var-medrt,\n \"usb\": $fa-var-usb,\n \"tumblr\": $fa-var-tumblr,\n \"vaadin\": $fa-var-vaadin,\n \"quora\": $fa-var-quora,\n \"square-x-twitter\": $fa-var-square-x-twitter,\n \"reacteurope\": $fa-var-reacteurope,\n \"medium\": $fa-var-medium,\n \"medium-m\": $fa-var-medium-m,\n \"amilia\": $fa-var-amilia,\n \"mixcloud\": $fa-var-mixcloud,\n \"flipboard\": $fa-var-flipboard,\n \"viacoin\": $fa-var-viacoin,\n \"critical-role\": $fa-var-critical-role,\n \"sitrox\": $fa-var-sitrox,\n \"discourse\": $fa-var-discourse,\n \"joomla\": $fa-var-joomla,\n \"mastodon\": $fa-var-mastodon,\n \"airbnb\": $fa-var-airbnb,\n \"wolf-pack-battalion\": $fa-var-wolf-pack-battalion,\n \"buy-n-large\": $fa-var-buy-n-large,\n \"gulp\": $fa-var-gulp,\n \"creative-commons-sampling-plus\": $fa-var-creative-commons-sampling-plus,\n \"strava\": $fa-var-strava,\n \"ember\": $fa-var-ember,\n \"canadian-maple-leaf\": $fa-var-canadian-maple-leaf,\n \"teamspeak\": $fa-var-teamspeak,\n \"pushed\": $fa-var-pushed,\n \"wordpress-simple\": $fa-var-wordpress-simple,\n \"nutritionix\": $fa-var-nutritionix,\n \"wodu\": $fa-var-wodu,\n \"google-pay\": $fa-var-google-pay,\n \"intercom\": $fa-var-intercom,\n \"zhihu\": $fa-var-zhihu,\n \"korvue\": $fa-var-korvue,\n \"pix\": $fa-var-pix,\n \"steam-symbol\": $fa-var-steam-symbol,\n);\n", + "/*!\n * Font Awesome Free 6.7.1 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n * Copyright 2024 Fonticons, Inc.\n */\n@import 'functions';\n@import 'variables';\n\n:root, :host {\n --#{$fa-css-prefix}-style-family-classic: '#{ $fa-style-family }';\n --#{$fa-css-prefix}-font-solid: normal 900 1em/1 '#{ $fa-style-family }';\n}\n\n\n@font-face {\n font-family: 'Font Awesome 6 Free';\n font-style: normal;\n font-weight: 900;\n font-display: $fa-font-display;\n src: url('#{$fa-font-path}/fa-solid-900.woff2') format('woff2'),\n url('#{$fa-font-path}/fa-solid-900.ttf') format('truetype');\n}\n\n.fas,\n.#{$fa-css-prefix}-solid {\n font-weight: 900;\n}\n", + "// functions\n// --------------------------\n\n// fa-content: convenience function used to set content property\n@function fa-content($fa-var) {\n @return unquote(\"\\\"#{ $fa-var }\\\"\");\n}\n\n// fa-divide: Originally obtained from the Bootstrap https://github.com/twbs/bootstrap\n//\n// Licensed under: The MIT License (MIT)\n//\n// Copyright (c) 2011-2021 Twitter, Inc.\n// Copyright (c) 2011-2021 The Bootstrap Authors\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n@function fa-divide($dividend, $divisor, $precision: 10) {\n $sign: if($dividend > 0 and $divisor > 0, 1, -1);\n $dividend: abs($dividend);\n $divisor: abs($divisor);\n $quotient: 0;\n $remainder: $dividend;\n @if $dividend == 0 {\n @return 0;\n }\n @if $divisor == 0 {\n @error \"Cannot divide by 0\";\n }\n @if $divisor == 1 {\n @return $dividend;\n }\n @while $remainder >= $divisor {\n $quotient: $quotient + 1;\n $remainder: $remainder - $divisor;\n }\n @if $remainder > 0 and $precision > 0 {\n $remainder: fa-divide($remainder * 10, $divisor, $precision - 1) * .1;\n }\n @return ($quotient + $remainder) * $sign;\n}\n", + "// variables\n// --------------------------\n\n$fa-css-prefix : fa !default;\n$fa-style : 900 !default;\n$fa-style-family : \"Font Awesome 6 Free\" !default;\n\n$fa-icon-property : --fa;\n$fa-duotone-icon-property : --fa--fa;\n\n$fa-display : inline-block !default;\n\n$fa-fw-width : fa-divide(20em, 16) !default;\n$fa-inverse : #fff !default;\n\n$fa-border-color : #eee !default;\n$fa-border-padding : .2em .25em .15em !default;\n$fa-border-radius : .1em !default;\n$fa-border-style : solid !default;\n$fa-border-width : .08em !default;\n\n$fa-size-scale-2xs : 10 !default;\n$fa-size-scale-xs : 12 !default;\n$fa-size-scale-sm : 14 !default;\n$fa-size-scale-base : 16 !default;\n$fa-size-scale-lg : 20 !default;\n$fa-size-scale-xl : 24 !default;\n$fa-size-scale-2xl : 32 !default;\n\n$fa-sizes: (\n \"2xs\" : $fa-size-scale-2xs,\n \"xs\" : $fa-size-scale-xs,\n \"sm\" : $fa-size-scale-sm,\n \"lg\" : $fa-size-scale-lg,\n \"xl\" : $fa-size-scale-xl,\n \"2xl\" : $fa-size-scale-2xl\n) !default;\n\n$fa-li-width : 2em !default;\n$fa-li-margin : $fa-li-width * fa-divide(5, 4) !default;\n\n$fa-pull-margin : .3em !default;\n\n$fa-primary-opacity : 1 !default;\n$fa-secondary-opacity : .4 !default;\n\n$fa-stack-vertical-align : middle !default;\n$fa-stack-width : ($fa-fw-width * 2) !default;\n$fa-stack-z-index : auto !default;\n\n$fa-font-display : block !default;\n$fa-font-path : \"../webfonts\" !default;\n\n$fa-var-0: \\30;\n$fa-var-1: \\31;\n$fa-var-2: \\32;\n$fa-var-3: \\33;\n$fa-var-4: \\34;\n$fa-var-5: \\35;\n$fa-var-6: \\36;\n$fa-var-7: \\37;\n$fa-var-8: \\38;\n$fa-var-9: \\39;\n$fa-var-fill-drip: \\f576;\n$fa-var-arrows-to-circle: \\e4bd;\n$fa-var-circle-chevron-right: \\f138;\n$fa-var-chevron-circle-right: \\f138;\n$fa-var-at: \\40;\n$fa-var-trash-can: \\f2ed;\n$fa-var-trash-alt: \\f2ed;\n$fa-var-text-height: \\f034;\n$fa-var-user-xmark: \\f235;\n$fa-var-user-times: \\f235;\n$fa-var-stethoscope: \\f0f1;\n$fa-var-message: \\f27a;\n$fa-var-comment-alt: \\f27a;\n$fa-var-info: \\f129;\n$fa-var-down-left-and-up-right-to-center: \\f422;\n$fa-var-compress-alt: \\f422;\n$fa-var-explosion: \\e4e9;\n$fa-var-file-lines: \\f15c;\n$fa-var-file-alt: \\f15c;\n$fa-var-file-text: \\f15c;\n$fa-var-wave-square: \\f83e;\n$fa-var-ring: \\f70b;\n$fa-var-building-un: \\e4d9;\n$fa-var-dice-three: \\f527;\n$fa-var-calendar-days: \\f073;\n$fa-var-calendar-alt: \\f073;\n$fa-var-anchor-circle-check: \\e4aa;\n$fa-var-building-circle-arrow-right: \\e4d1;\n$fa-var-volleyball: \\f45f;\n$fa-var-volleyball-ball: \\f45f;\n$fa-var-arrows-up-to-line: \\e4c2;\n$fa-var-sort-down: \\f0dd;\n$fa-var-sort-desc: \\f0dd;\n$fa-var-circle-minus: \\f056;\n$fa-var-minus-circle: \\f056;\n$fa-var-door-open: \\f52b;\n$fa-var-right-from-bracket: \\f2f5;\n$fa-var-sign-out-alt: \\f2f5;\n$fa-var-atom: \\f5d2;\n$fa-var-soap: \\e06e;\n$fa-var-icons: \\f86d;\n$fa-var-heart-music-camera-bolt: \\f86d;\n$fa-var-microphone-lines-slash: \\f539;\n$fa-var-microphone-alt-slash: \\f539;\n$fa-var-bridge-circle-check: \\e4c9;\n$fa-var-pump-medical: \\e06a;\n$fa-var-fingerprint: \\f577;\n$fa-var-hand-point-right: \\f0a4;\n$fa-var-magnifying-glass-location: \\f689;\n$fa-var-search-location: \\f689;\n$fa-var-forward-step: \\f051;\n$fa-var-step-forward: \\f051;\n$fa-var-face-smile-beam: \\f5b8;\n$fa-var-smile-beam: \\f5b8;\n$fa-var-flag-checkered: \\f11e;\n$fa-var-football: \\f44e;\n$fa-var-football-ball: \\f44e;\n$fa-var-school-circle-exclamation: \\e56c;\n$fa-var-crop: \\f125;\n$fa-var-angles-down: \\f103;\n$fa-var-angle-double-down: \\f103;\n$fa-var-users-rectangle: \\e594;\n$fa-var-people-roof: \\e537;\n$fa-var-people-line: \\e534;\n$fa-var-beer-mug-empty: \\f0fc;\n$fa-var-beer: \\f0fc;\n$fa-var-diagram-predecessor: \\e477;\n$fa-var-arrow-up-long: \\f176;\n$fa-var-long-arrow-up: \\f176;\n$fa-var-fire-flame-simple: \\f46a;\n$fa-var-burn: \\f46a;\n$fa-var-person: \\f183;\n$fa-var-male: \\f183;\n$fa-var-laptop: \\f109;\n$fa-var-file-csv: \\f6dd;\n$fa-var-menorah: \\f676;\n$fa-var-truck-plane: \\e58f;\n$fa-var-record-vinyl: \\f8d9;\n$fa-var-face-grin-stars: \\f587;\n$fa-var-grin-stars: \\f587;\n$fa-var-bong: \\f55c;\n$fa-var-spaghetti-monster-flying: \\f67b;\n$fa-var-pastafarianism: \\f67b;\n$fa-var-arrow-down-up-across-line: \\e4af;\n$fa-var-spoon: \\f2e5;\n$fa-var-utensil-spoon: \\f2e5;\n$fa-var-jar-wheat: \\e517;\n$fa-var-envelopes-bulk: \\f674;\n$fa-var-mail-bulk: \\f674;\n$fa-var-file-circle-exclamation: \\e4eb;\n$fa-var-circle-h: \\f47e;\n$fa-var-hospital-symbol: \\f47e;\n$fa-var-pager: \\f815;\n$fa-var-address-book: \\f2b9;\n$fa-var-contact-book: \\f2b9;\n$fa-var-strikethrough: \\f0cc;\n$fa-var-k: \\4b;\n$fa-var-landmark-flag: \\e51c;\n$fa-var-pencil: \\f303;\n$fa-var-pencil-alt: \\f303;\n$fa-var-backward: \\f04a;\n$fa-var-caret-right: \\f0da;\n$fa-var-comments: \\f086;\n$fa-var-paste: \\f0ea;\n$fa-var-file-clipboard: \\f0ea;\n$fa-var-code-pull-request: \\e13c;\n$fa-var-clipboard-list: \\f46d;\n$fa-var-truck-ramp-box: \\f4de;\n$fa-var-truck-loading: \\f4de;\n$fa-var-user-check: \\f4fc;\n$fa-var-vial-virus: \\e597;\n$fa-var-sheet-plastic: \\e571;\n$fa-var-blog: \\f781;\n$fa-var-user-ninja: \\f504;\n$fa-var-person-arrow-up-from-line: \\e539;\n$fa-var-scroll-torah: \\f6a0;\n$fa-var-torah: \\f6a0;\n$fa-var-broom-ball: \\f458;\n$fa-var-quidditch: \\f458;\n$fa-var-quidditch-broom-ball: \\f458;\n$fa-var-toggle-off: \\f204;\n$fa-var-box-archive: \\f187;\n$fa-var-archive: \\f187;\n$fa-var-person-drowning: \\e545;\n$fa-var-arrow-down-9-1: \\f886;\n$fa-var-sort-numeric-desc: \\f886;\n$fa-var-sort-numeric-down-alt: \\f886;\n$fa-var-face-grin-tongue-squint: \\f58a;\n$fa-var-grin-tongue-squint: \\f58a;\n$fa-var-spray-can: \\f5bd;\n$fa-var-truck-monster: \\f63b;\n$fa-var-w: \\57;\n$fa-var-earth-africa: \\f57c;\n$fa-var-globe-africa: \\f57c;\n$fa-var-rainbow: \\f75b;\n$fa-var-circle-notch: \\f1ce;\n$fa-var-tablet-screen-button: \\f3fa;\n$fa-var-tablet-alt: \\f3fa;\n$fa-var-paw: \\f1b0;\n$fa-var-cloud: \\f0c2;\n$fa-var-trowel-bricks: \\e58a;\n$fa-var-face-flushed: \\f579;\n$fa-var-flushed: \\f579;\n$fa-var-hospital-user: \\f80d;\n$fa-var-tent-arrow-left-right: \\e57f;\n$fa-var-gavel: \\f0e3;\n$fa-var-legal: \\f0e3;\n$fa-var-binoculars: \\f1e5;\n$fa-var-microphone-slash: \\f131;\n$fa-var-box-tissue: \\e05b;\n$fa-var-motorcycle: \\f21c;\n$fa-var-bell-concierge: \\f562;\n$fa-var-concierge-bell: \\f562;\n$fa-var-pen-ruler: \\f5ae;\n$fa-var-pencil-ruler: \\f5ae;\n$fa-var-people-arrows: \\e068;\n$fa-var-people-arrows-left-right: \\e068;\n$fa-var-mars-and-venus-burst: \\e523;\n$fa-var-square-caret-right: \\f152;\n$fa-var-caret-square-right: \\f152;\n$fa-var-scissors: \\f0c4;\n$fa-var-cut: \\f0c4;\n$fa-var-sun-plant-wilt: \\e57a;\n$fa-var-toilets-portable: \\e584;\n$fa-var-hockey-puck: \\f453;\n$fa-var-table: \\f0ce;\n$fa-var-magnifying-glass-arrow-right: \\e521;\n$fa-var-tachograph-digital: \\f566;\n$fa-var-digital-tachograph: \\f566;\n$fa-var-users-slash: \\e073;\n$fa-var-clover: \\e139;\n$fa-var-reply: \\f3e5;\n$fa-var-mail-reply: \\f3e5;\n$fa-var-star-and-crescent: \\f699;\n$fa-var-house-fire: \\e50c;\n$fa-var-square-minus: \\f146;\n$fa-var-minus-square: \\f146;\n$fa-var-helicopter: \\f533;\n$fa-var-compass: \\f14e;\n$fa-var-square-caret-down: \\f150;\n$fa-var-caret-square-down: \\f150;\n$fa-var-file-circle-question: \\e4ef;\n$fa-var-laptop-code: \\f5fc;\n$fa-var-swatchbook: \\f5c3;\n$fa-var-prescription-bottle: \\f485;\n$fa-var-bars: \\f0c9;\n$fa-var-navicon: \\f0c9;\n$fa-var-people-group: \\e533;\n$fa-var-hourglass-end: \\f253;\n$fa-var-hourglass-3: \\f253;\n$fa-var-heart-crack: \\f7a9;\n$fa-var-heart-broken: \\f7a9;\n$fa-var-square-up-right: \\f360;\n$fa-var-external-link-square-alt: \\f360;\n$fa-var-face-kiss-beam: \\f597;\n$fa-var-kiss-beam: \\f597;\n$fa-var-film: \\f008;\n$fa-var-ruler-horizontal: \\f547;\n$fa-var-people-robbery: \\e536;\n$fa-var-lightbulb: \\f0eb;\n$fa-var-caret-left: \\f0d9;\n$fa-var-circle-exclamation: \\f06a;\n$fa-var-exclamation-circle: \\f06a;\n$fa-var-school-circle-xmark: \\e56d;\n$fa-var-arrow-right-from-bracket: \\f08b;\n$fa-var-sign-out: \\f08b;\n$fa-var-circle-chevron-down: \\f13a;\n$fa-var-chevron-circle-down: \\f13a;\n$fa-var-unlock-keyhole: \\f13e;\n$fa-var-unlock-alt: \\f13e;\n$fa-var-cloud-showers-heavy: \\f740;\n$fa-var-headphones-simple: \\f58f;\n$fa-var-headphones-alt: \\f58f;\n$fa-var-sitemap: \\f0e8;\n$fa-var-circle-dollar-to-slot: \\f4b9;\n$fa-var-donate: \\f4b9;\n$fa-var-memory: \\f538;\n$fa-var-road-spikes: \\e568;\n$fa-var-fire-burner: \\e4f1;\n$fa-var-flag: \\f024;\n$fa-var-hanukiah: \\f6e6;\n$fa-var-feather: \\f52d;\n$fa-var-volume-low: \\f027;\n$fa-var-volume-down: \\f027;\n$fa-var-comment-slash: \\f4b3;\n$fa-var-cloud-sun-rain: \\f743;\n$fa-var-compress: \\f066;\n$fa-var-wheat-awn: \\e2cd;\n$fa-var-wheat-alt: \\e2cd;\n$fa-var-ankh: \\f644;\n$fa-var-hands-holding-child: \\e4fa;\n$fa-var-asterisk: \\2a;\n$fa-var-square-check: \\f14a;\n$fa-var-check-square: \\f14a;\n$fa-var-peseta-sign: \\e221;\n$fa-var-heading: \\f1dc;\n$fa-var-header: \\f1dc;\n$fa-var-ghost: \\f6e2;\n$fa-var-list: \\f03a;\n$fa-var-list-squares: \\f03a;\n$fa-var-square-phone-flip: \\f87b;\n$fa-var-phone-square-alt: \\f87b;\n$fa-var-cart-plus: \\f217;\n$fa-var-gamepad: \\f11b;\n$fa-var-circle-dot: \\f192;\n$fa-var-dot-circle: \\f192;\n$fa-var-face-dizzy: \\f567;\n$fa-var-dizzy: \\f567;\n$fa-var-egg: \\f7fb;\n$fa-var-house-medical-circle-xmark: \\e513;\n$fa-var-campground: \\f6bb;\n$fa-var-folder-plus: \\f65e;\n$fa-var-futbol: \\f1e3;\n$fa-var-futbol-ball: \\f1e3;\n$fa-var-soccer-ball: \\f1e3;\n$fa-var-paintbrush: \\f1fc;\n$fa-var-paint-brush: \\f1fc;\n$fa-var-lock: \\f023;\n$fa-var-gas-pump: \\f52f;\n$fa-var-hot-tub-person: \\f593;\n$fa-var-hot-tub: \\f593;\n$fa-var-map-location: \\f59f;\n$fa-var-map-marked: \\f59f;\n$fa-var-house-flood-water: \\e50e;\n$fa-var-tree: \\f1bb;\n$fa-var-bridge-lock: \\e4cc;\n$fa-var-sack-dollar: \\f81d;\n$fa-var-pen-to-square: \\f044;\n$fa-var-edit: \\f044;\n$fa-var-car-side: \\f5e4;\n$fa-var-share-nodes: \\f1e0;\n$fa-var-share-alt: \\f1e0;\n$fa-var-heart-circle-minus: \\e4ff;\n$fa-var-hourglass-half: \\f252;\n$fa-var-hourglass-2: \\f252;\n$fa-var-microscope: \\f610;\n$fa-var-sink: \\e06d;\n$fa-var-bag-shopping: \\f290;\n$fa-var-shopping-bag: \\f290;\n$fa-var-arrow-down-z-a: \\f881;\n$fa-var-sort-alpha-desc: \\f881;\n$fa-var-sort-alpha-down-alt: \\f881;\n$fa-var-mitten: \\f7b5;\n$fa-var-person-rays: \\e54d;\n$fa-var-users: \\f0c0;\n$fa-var-eye-slash: \\f070;\n$fa-var-flask-vial: \\e4f3;\n$fa-var-hand: \\f256;\n$fa-var-hand-paper: \\f256;\n$fa-var-om: \\f679;\n$fa-var-worm: \\e599;\n$fa-var-house-circle-xmark: \\e50b;\n$fa-var-plug: \\f1e6;\n$fa-var-chevron-up: \\f077;\n$fa-var-hand-spock: \\f259;\n$fa-var-stopwatch: \\f2f2;\n$fa-var-face-kiss: \\f596;\n$fa-var-kiss: \\f596;\n$fa-var-bridge-circle-xmark: \\e4cb;\n$fa-var-face-grin-tongue: \\f589;\n$fa-var-grin-tongue: \\f589;\n$fa-var-chess-bishop: \\f43a;\n$fa-var-face-grin-wink: \\f58c;\n$fa-var-grin-wink: \\f58c;\n$fa-var-ear-deaf: \\f2a4;\n$fa-var-deaf: \\f2a4;\n$fa-var-deafness: \\f2a4;\n$fa-var-hard-of-hearing: \\f2a4;\n$fa-var-road-circle-check: \\e564;\n$fa-var-dice-five: \\f523;\n$fa-var-square-rss: \\f143;\n$fa-var-rss-square: \\f143;\n$fa-var-land-mine-on: \\e51b;\n$fa-var-i-cursor: \\f246;\n$fa-var-stamp: \\f5bf;\n$fa-var-stairs: \\e289;\n$fa-var-i: \\49;\n$fa-var-hryvnia-sign: \\f6f2;\n$fa-var-hryvnia: \\f6f2;\n$fa-var-pills: \\f484;\n$fa-var-face-grin-wide: \\f581;\n$fa-var-grin-alt: \\f581;\n$fa-var-tooth: \\f5c9;\n$fa-var-v: \\56;\n$fa-var-bangladeshi-taka-sign: \\e2e6;\n$fa-var-bicycle: \\f206;\n$fa-var-staff-snake: \\e579;\n$fa-var-rod-asclepius: \\e579;\n$fa-var-rod-snake: \\e579;\n$fa-var-staff-aesculapius: \\e579;\n$fa-var-head-side-cough-slash: \\e062;\n$fa-var-truck-medical: \\f0f9;\n$fa-var-ambulance: \\f0f9;\n$fa-var-wheat-awn-circle-exclamation: \\e598;\n$fa-var-snowman: \\f7d0;\n$fa-var-mortar-pestle: \\f5a7;\n$fa-var-road-barrier: \\e562;\n$fa-var-school: \\f549;\n$fa-var-igloo: \\f7ae;\n$fa-var-joint: \\f595;\n$fa-var-angle-right: \\f105;\n$fa-var-horse: \\f6f0;\n$fa-var-q: \\51;\n$fa-var-g: \\47;\n$fa-var-notes-medical: \\f481;\n$fa-var-temperature-half: \\f2c9;\n$fa-var-temperature-2: \\f2c9;\n$fa-var-thermometer-2: \\f2c9;\n$fa-var-thermometer-half: \\f2c9;\n$fa-var-dong-sign: \\e169;\n$fa-var-capsules: \\f46b;\n$fa-var-poo-storm: \\f75a;\n$fa-var-poo-bolt: \\f75a;\n$fa-var-face-frown-open: \\f57a;\n$fa-var-frown-open: \\f57a;\n$fa-var-hand-point-up: \\f0a6;\n$fa-var-money-bill: \\f0d6;\n$fa-var-bookmark: \\f02e;\n$fa-var-align-justify: \\f039;\n$fa-var-umbrella-beach: \\f5ca;\n$fa-var-helmet-un: \\e503;\n$fa-var-bullseye: \\f140;\n$fa-var-bacon: \\f7e5;\n$fa-var-hand-point-down: \\f0a7;\n$fa-var-arrow-up-from-bracket: \\e09a;\n$fa-var-folder: \\f07b;\n$fa-var-folder-blank: \\f07b;\n$fa-var-file-waveform: \\f478;\n$fa-var-file-medical-alt: \\f478;\n$fa-var-radiation: \\f7b9;\n$fa-var-chart-simple: \\e473;\n$fa-var-mars-stroke: \\f229;\n$fa-var-vial: \\f492;\n$fa-var-gauge: \\f624;\n$fa-var-dashboard: \\f624;\n$fa-var-gauge-med: \\f624;\n$fa-var-tachometer-alt-average: \\f624;\n$fa-var-wand-magic-sparkles: \\e2ca;\n$fa-var-magic-wand-sparkles: \\e2ca;\n$fa-var-e: \\45;\n$fa-var-pen-clip: \\f305;\n$fa-var-pen-alt: \\f305;\n$fa-var-bridge-circle-exclamation: \\e4ca;\n$fa-var-user: \\f007;\n$fa-var-school-circle-check: \\e56b;\n$fa-var-dumpster: \\f793;\n$fa-var-van-shuttle: \\f5b6;\n$fa-var-shuttle-van: \\f5b6;\n$fa-var-building-user: \\e4da;\n$fa-var-square-caret-left: \\f191;\n$fa-var-caret-square-left: \\f191;\n$fa-var-highlighter: \\f591;\n$fa-var-key: \\f084;\n$fa-var-bullhorn: \\f0a1;\n$fa-var-globe: \\f0ac;\n$fa-var-synagogue: \\f69b;\n$fa-var-person-half-dress: \\e548;\n$fa-var-road-bridge: \\e563;\n$fa-var-location-arrow: \\f124;\n$fa-var-c: \\43;\n$fa-var-tablet-button: \\f10a;\n$fa-var-building-lock: \\e4d6;\n$fa-var-pizza-slice: \\f818;\n$fa-var-money-bill-wave: \\f53a;\n$fa-var-chart-area: \\f1fe;\n$fa-var-area-chart: \\f1fe;\n$fa-var-house-flag: \\e50d;\n$fa-var-person-circle-minus: \\e540;\n$fa-var-ban: \\f05e;\n$fa-var-cancel: \\f05e;\n$fa-var-camera-rotate: \\e0d8;\n$fa-var-spray-can-sparkles: \\f5d0;\n$fa-var-air-freshener: \\f5d0;\n$fa-var-star: \\f005;\n$fa-var-repeat: \\f363;\n$fa-var-cross: \\f654;\n$fa-var-box: \\f466;\n$fa-var-venus-mars: \\f228;\n$fa-var-arrow-pointer: \\f245;\n$fa-var-mouse-pointer: \\f245;\n$fa-var-maximize: \\f31e;\n$fa-var-expand-arrows-alt: \\f31e;\n$fa-var-charging-station: \\f5e7;\n$fa-var-shapes: \\f61f;\n$fa-var-triangle-circle-square: \\f61f;\n$fa-var-shuffle: \\f074;\n$fa-var-random: \\f074;\n$fa-var-person-running: \\f70c;\n$fa-var-running: \\f70c;\n$fa-var-mobile-retro: \\e527;\n$fa-var-grip-lines-vertical: \\f7a5;\n$fa-var-spider: \\f717;\n$fa-var-hands-bound: \\e4f9;\n$fa-var-file-invoice-dollar: \\f571;\n$fa-var-plane-circle-exclamation: \\e556;\n$fa-var-x-ray: \\f497;\n$fa-var-spell-check: \\f891;\n$fa-var-slash: \\f715;\n$fa-var-computer-mouse: \\f8cc;\n$fa-var-mouse: \\f8cc;\n$fa-var-arrow-right-to-bracket: \\f090;\n$fa-var-sign-in: \\f090;\n$fa-var-shop-slash: \\e070;\n$fa-var-store-alt-slash: \\e070;\n$fa-var-server: \\f233;\n$fa-var-virus-covid-slash: \\e4a9;\n$fa-var-shop-lock: \\e4a5;\n$fa-var-hourglass-start: \\f251;\n$fa-var-hourglass-1: \\f251;\n$fa-var-blender-phone: \\f6b6;\n$fa-var-building-wheat: \\e4db;\n$fa-var-person-breastfeeding: \\e53a;\n$fa-var-right-to-bracket: \\f2f6;\n$fa-var-sign-in-alt: \\f2f6;\n$fa-var-venus: \\f221;\n$fa-var-passport: \\f5ab;\n$fa-var-thumbtack-slash: \\e68f;\n$fa-var-thumb-tack-slash: \\e68f;\n$fa-var-heart-pulse: \\f21e;\n$fa-var-heartbeat: \\f21e;\n$fa-var-people-carry-box: \\f4ce;\n$fa-var-people-carry: \\f4ce;\n$fa-var-temperature-high: \\f769;\n$fa-var-microchip: \\f2db;\n$fa-var-crown: \\f521;\n$fa-var-weight-hanging: \\f5cd;\n$fa-var-xmarks-lines: \\e59a;\n$fa-var-file-prescription: \\f572;\n$fa-var-weight-scale: \\f496;\n$fa-var-weight: \\f496;\n$fa-var-user-group: \\f500;\n$fa-var-user-friends: \\f500;\n$fa-var-arrow-up-a-z: \\f15e;\n$fa-var-sort-alpha-up: \\f15e;\n$fa-var-chess-knight: \\f441;\n$fa-var-face-laugh-squint: \\f59b;\n$fa-var-laugh-squint: \\f59b;\n$fa-var-wheelchair: \\f193;\n$fa-var-circle-arrow-up: \\f0aa;\n$fa-var-arrow-circle-up: \\f0aa;\n$fa-var-toggle-on: \\f205;\n$fa-var-person-walking: \\f554;\n$fa-var-walking: \\f554;\n$fa-var-l: \\4c;\n$fa-var-fire: \\f06d;\n$fa-var-bed-pulse: \\f487;\n$fa-var-procedures: \\f487;\n$fa-var-shuttle-space: \\f197;\n$fa-var-space-shuttle: \\f197;\n$fa-var-face-laugh: \\f599;\n$fa-var-laugh: \\f599;\n$fa-var-folder-open: \\f07c;\n$fa-var-heart-circle-plus: \\e500;\n$fa-var-code-fork: \\e13b;\n$fa-var-city: \\f64f;\n$fa-var-microphone-lines: \\f3c9;\n$fa-var-microphone-alt: \\f3c9;\n$fa-var-pepper-hot: \\f816;\n$fa-var-unlock: \\f09c;\n$fa-var-colon-sign: \\e140;\n$fa-var-headset: \\f590;\n$fa-var-store-slash: \\e071;\n$fa-var-road-circle-xmark: \\e566;\n$fa-var-user-minus: \\f503;\n$fa-var-mars-stroke-up: \\f22a;\n$fa-var-mars-stroke-v: \\f22a;\n$fa-var-champagne-glasses: \\f79f;\n$fa-var-glass-cheers: \\f79f;\n$fa-var-clipboard: \\f328;\n$fa-var-house-circle-exclamation: \\e50a;\n$fa-var-file-arrow-up: \\f574;\n$fa-var-file-upload: \\f574;\n$fa-var-wifi: \\f1eb;\n$fa-var-wifi-3: \\f1eb;\n$fa-var-wifi-strong: \\f1eb;\n$fa-var-bath: \\f2cd;\n$fa-var-bathtub: \\f2cd;\n$fa-var-underline: \\f0cd;\n$fa-var-user-pen: \\f4ff;\n$fa-var-user-edit: \\f4ff;\n$fa-var-signature: \\f5b7;\n$fa-var-stroopwafel: \\f551;\n$fa-var-bold: \\f032;\n$fa-var-anchor-lock: \\e4ad;\n$fa-var-building-ngo: \\e4d7;\n$fa-var-manat-sign: \\e1d5;\n$fa-var-not-equal: \\f53e;\n$fa-var-border-top-left: \\f853;\n$fa-var-border-style: \\f853;\n$fa-var-map-location-dot: \\f5a0;\n$fa-var-map-marked-alt: \\f5a0;\n$fa-var-jedi: \\f669;\n$fa-var-square-poll-vertical: \\f681;\n$fa-var-poll: \\f681;\n$fa-var-mug-hot: \\f7b6;\n$fa-var-car-battery: \\f5df;\n$fa-var-battery-car: \\f5df;\n$fa-var-gift: \\f06b;\n$fa-var-dice-two: \\f528;\n$fa-var-chess-queen: \\f445;\n$fa-var-glasses: \\f530;\n$fa-var-chess-board: \\f43c;\n$fa-var-building-circle-check: \\e4d2;\n$fa-var-person-chalkboard: \\e53d;\n$fa-var-mars-stroke-right: \\f22b;\n$fa-var-mars-stroke-h: \\f22b;\n$fa-var-hand-back-fist: \\f255;\n$fa-var-hand-rock: \\f255;\n$fa-var-square-caret-up: \\f151;\n$fa-var-caret-square-up: \\f151;\n$fa-var-cloud-showers-water: \\e4e4;\n$fa-var-chart-bar: \\f080;\n$fa-var-bar-chart: \\f080;\n$fa-var-hands-bubbles: \\e05e;\n$fa-var-hands-wash: \\e05e;\n$fa-var-less-than-equal: \\f537;\n$fa-var-train: \\f238;\n$fa-var-eye-low-vision: \\f2a8;\n$fa-var-low-vision: \\f2a8;\n$fa-var-crow: \\f520;\n$fa-var-sailboat: \\e445;\n$fa-var-window-restore: \\f2d2;\n$fa-var-square-plus: \\f0fe;\n$fa-var-plus-square: \\f0fe;\n$fa-var-torii-gate: \\f6a1;\n$fa-var-frog: \\f52e;\n$fa-var-bucket: \\e4cf;\n$fa-var-image: \\f03e;\n$fa-var-microphone: \\f130;\n$fa-var-cow: \\f6c8;\n$fa-var-caret-up: \\f0d8;\n$fa-var-screwdriver: \\f54a;\n$fa-var-folder-closed: \\e185;\n$fa-var-house-tsunami: \\e515;\n$fa-var-square-nfi: \\e576;\n$fa-var-arrow-up-from-ground-water: \\e4b5;\n$fa-var-martini-glass: \\f57b;\n$fa-var-glass-martini-alt: \\f57b;\n$fa-var-square-binary: \\e69b;\n$fa-var-rotate-left: \\f2ea;\n$fa-var-rotate-back: \\f2ea;\n$fa-var-rotate-backward: \\f2ea;\n$fa-var-undo-alt: \\f2ea;\n$fa-var-table-columns: \\f0db;\n$fa-var-columns: \\f0db;\n$fa-var-lemon: \\f094;\n$fa-var-head-side-mask: \\e063;\n$fa-var-handshake: \\f2b5;\n$fa-var-gem: \\f3a5;\n$fa-var-dolly: \\f472;\n$fa-var-dolly-box: \\f472;\n$fa-var-smoking: \\f48d;\n$fa-var-minimize: \\f78c;\n$fa-var-compress-arrows-alt: \\f78c;\n$fa-var-monument: \\f5a6;\n$fa-var-snowplow: \\f7d2;\n$fa-var-angles-right: \\f101;\n$fa-var-angle-double-right: \\f101;\n$fa-var-cannabis: \\f55f;\n$fa-var-circle-play: \\f144;\n$fa-var-play-circle: \\f144;\n$fa-var-tablets: \\f490;\n$fa-var-ethernet: \\f796;\n$fa-var-euro-sign: \\f153;\n$fa-var-eur: \\f153;\n$fa-var-euro: \\f153;\n$fa-var-chair: \\f6c0;\n$fa-var-circle-check: \\f058;\n$fa-var-check-circle: \\f058;\n$fa-var-circle-stop: \\f28d;\n$fa-var-stop-circle: \\f28d;\n$fa-var-compass-drafting: \\f568;\n$fa-var-drafting-compass: \\f568;\n$fa-var-plate-wheat: \\e55a;\n$fa-var-icicles: \\f7ad;\n$fa-var-person-shelter: \\e54f;\n$fa-var-neuter: \\f22c;\n$fa-var-id-badge: \\f2c1;\n$fa-var-marker: \\f5a1;\n$fa-var-face-laugh-beam: \\f59a;\n$fa-var-laugh-beam: \\f59a;\n$fa-var-helicopter-symbol: \\e502;\n$fa-var-universal-access: \\f29a;\n$fa-var-circle-chevron-up: \\f139;\n$fa-var-chevron-circle-up: \\f139;\n$fa-var-lari-sign: \\e1c8;\n$fa-var-volcano: \\f770;\n$fa-var-person-walking-dashed-line-arrow-right: \\e553;\n$fa-var-sterling-sign: \\f154;\n$fa-var-gbp: \\f154;\n$fa-var-pound-sign: \\f154;\n$fa-var-viruses: \\e076;\n$fa-var-square-person-confined: \\e577;\n$fa-var-user-tie: \\f508;\n$fa-var-arrow-down-long: \\f175;\n$fa-var-long-arrow-down: \\f175;\n$fa-var-tent-arrow-down-to-line: \\e57e;\n$fa-var-certificate: \\f0a3;\n$fa-var-reply-all: \\f122;\n$fa-var-mail-reply-all: \\f122;\n$fa-var-suitcase: \\f0f2;\n$fa-var-person-skating: \\f7c5;\n$fa-var-skating: \\f7c5;\n$fa-var-filter-circle-dollar: \\f662;\n$fa-var-funnel-dollar: \\f662;\n$fa-var-camera-retro: \\f083;\n$fa-var-circle-arrow-down: \\f0ab;\n$fa-var-arrow-circle-down: \\f0ab;\n$fa-var-file-import: \\f56f;\n$fa-var-arrow-right-to-file: \\f56f;\n$fa-var-square-arrow-up-right: \\f14c;\n$fa-var-external-link-square: \\f14c;\n$fa-var-box-open: \\f49e;\n$fa-var-scroll: \\f70e;\n$fa-var-spa: \\f5bb;\n$fa-var-location-pin-lock: \\e51f;\n$fa-var-pause: \\f04c;\n$fa-var-hill-avalanche: \\e507;\n$fa-var-temperature-empty: \\f2cb;\n$fa-var-temperature-0: \\f2cb;\n$fa-var-thermometer-0: \\f2cb;\n$fa-var-thermometer-empty: \\f2cb;\n$fa-var-bomb: \\f1e2;\n$fa-var-registered: \\f25d;\n$fa-var-address-card: \\f2bb;\n$fa-var-contact-card: \\f2bb;\n$fa-var-vcard: \\f2bb;\n$fa-var-scale-unbalanced-flip: \\f516;\n$fa-var-balance-scale-right: \\f516;\n$fa-var-subscript: \\f12c;\n$fa-var-diamond-turn-right: \\f5eb;\n$fa-var-directions: \\f5eb;\n$fa-var-burst: \\e4dc;\n$fa-var-house-laptop: \\e066;\n$fa-var-laptop-house: \\e066;\n$fa-var-face-tired: \\f5c8;\n$fa-var-tired: \\f5c8;\n$fa-var-money-bills: \\e1f3;\n$fa-var-smog: \\f75f;\n$fa-var-crutch: \\f7f7;\n$fa-var-cloud-arrow-up: \\f0ee;\n$fa-var-cloud-upload: \\f0ee;\n$fa-var-cloud-upload-alt: \\f0ee;\n$fa-var-palette: \\f53f;\n$fa-var-arrows-turn-right: \\e4c0;\n$fa-var-vest: \\e085;\n$fa-var-ferry: \\e4ea;\n$fa-var-arrows-down-to-people: \\e4b9;\n$fa-var-seedling: \\f4d8;\n$fa-var-sprout: \\f4d8;\n$fa-var-left-right: \\f337;\n$fa-var-arrows-alt-h: \\f337;\n$fa-var-boxes-packing: \\e4c7;\n$fa-var-circle-arrow-left: \\f0a8;\n$fa-var-arrow-circle-left: \\f0a8;\n$fa-var-group-arrows-rotate: \\e4f6;\n$fa-var-bowl-food: \\e4c6;\n$fa-var-candy-cane: \\f786;\n$fa-var-arrow-down-wide-short: \\f160;\n$fa-var-sort-amount-asc: \\f160;\n$fa-var-sort-amount-down: \\f160;\n$fa-var-cloud-bolt: \\f76c;\n$fa-var-thunderstorm: \\f76c;\n$fa-var-text-slash: \\f87d;\n$fa-var-remove-format: \\f87d;\n$fa-var-face-smile-wink: \\f4da;\n$fa-var-smile-wink: \\f4da;\n$fa-var-file-word: \\f1c2;\n$fa-var-file-powerpoint: \\f1c4;\n$fa-var-arrows-left-right: \\f07e;\n$fa-var-arrows-h: \\f07e;\n$fa-var-house-lock: \\e510;\n$fa-var-cloud-arrow-down: \\f0ed;\n$fa-var-cloud-download: \\f0ed;\n$fa-var-cloud-download-alt: \\f0ed;\n$fa-var-children: \\e4e1;\n$fa-var-chalkboard: \\f51b;\n$fa-var-blackboard: \\f51b;\n$fa-var-user-large-slash: \\f4fa;\n$fa-var-user-alt-slash: \\f4fa;\n$fa-var-envelope-open: \\f2b6;\n$fa-var-handshake-simple-slash: \\e05f;\n$fa-var-handshake-alt-slash: \\e05f;\n$fa-var-mattress-pillow: \\e525;\n$fa-var-guarani-sign: \\e19a;\n$fa-var-arrows-rotate: \\f021;\n$fa-var-refresh: \\f021;\n$fa-var-sync: \\f021;\n$fa-var-fire-extinguisher: \\f134;\n$fa-var-cruzeiro-sign: \\e152;\n$fa-var-greater-than-equal: \\f532;\n$fa-var-shield-halved: \\f3ed;\n$fa-var-shield-alt: \\f3ed;\n$fa-var-book-atlas: \\f558;\n$fa-var-atlas: \\f558;\n$fa-var-virus: \\e074;\n$fa-var-envelope-circle-check: \\e4e8;\n$fa-var-layer-group: \\f5fd;\n$fa-var-arrows-to-dot: \\e4be;\n$fa-var-archway: \\f557;\n$fa-var-heart-circle-check: \\e4fd;\n$fa-var-house-chimney-crack: \\f6f1;\n$fa-var-house-damage: \\f6f1;\n$fa-var-file-zipper: \\f1c6;\n$fa-var-file-archive: \\f1c6;\n$fa-var-square: \\f0c8;\n$fa-var-martini-glass-empty: \\f000;\n$fa-var-glass-martini: \\f000;\n$fa-var-couch: \\f4b8;\n$fa-var-cedi-sign: \\e0df;\n$fa-var-italic: \\f033;\n$fa-var-table-cells-column-lock: \\e678;\n$fa-var-church: \\f51d;\n$fa-var-comments-dollar: \\f653;\n$fa-var-democrat: \\f747;\n$fa-var-z: \\5a;\n$fa-var-person-skiing: \\f7c9;\n$fa-var-skiing: \\f7c9;\n$fa-var-road-lock: \\e567;\n$fa-var-a: \\41;\n$fa-var-temperature-arrow-down: \\e03f;\n$fa-var-temperature-down: \\e03f;\n$fa-var-feather-pointed: \\f56b;\n$fa-var-feather-alt: \\f56b;\n$fa-var-p: \\50;\n$fa-var-snowflake: \\f2dc;\n$fa-var-newspaper: \\f1ea;\n$fa-var-rectangle-ad: \\f641;\n$fa-var-ad: \\f641;\n$fa-var-circle-arrow-right: \\f0a9;\n$fa-var-arrow-circle-right: \\f0a9;\n$fa-var-filter-circle-xmark: \\e17b;\n$fa-var-locust: \\e520;\n$fa-var-sort: \\f0dc;\n$fa-var-unsorted: \\f0dc;\n$fa-var-list-ol: \\f0cb;\n$fa-var-list-1-2: \\f0cb;\n$fa-var-list-numeric: \\f0cb;\n$fa-var-person-dress-burst: \\e544;\n$fa-var-money-check-dollar: \\f53d;\n$fa-var-money-check-alt: \\f53d;\n$fa-var-vector-square: \\f5cb;\n$fa-var-bread-slice: \\f7ec;\n$fa-var-language: \\f1ab;\n$fa-var-face-kiss-wink-heart: \\f598;\n$fa-var-kiss-wink-heart: \\f598;\n$fa-var-filter: \\f0b0;\n$fa-var-question: \\3f;\n$fa-var-file-signature: \\f573;\n$fa-var-up-down-left-right: \\f0b2;\n$fa-var-arrows-alt: \\f0b2;\n$fa-var-house-chimney-user: \\e065;\n$fa-var-hand-holding-heart: \\f4be;\n$fa-var-puzzle-piece: \\f12e;\n$fa-var-money-check: \\f53c;\n$fa-var-star-half-stroke: \\f5c0;\n$fa-var-star-half-alt: \\f5c0;\n$fa-var-code: \\f121;\n$fa-var-whiskey-glass: \\f7a0;\n$fa-var-glass-whiskey: \\f7a0;\n$fa-var-building-circle-exclamation: \\e4d3;\n$fa-var-magnifying-glass-chart: \\e522;\n$fa-var-arrow-up-right-from-square: \\f08e;\n$fa-var-external-link: \\f08e;\n$fa-var-cubes-stacked: \\e4e6;\n$fa-var-won-sign: \\f159;\n$fa-var-krw: \\f159;\n$fa-var-won: \\f159;\n$fa-var-virus-covid: \\e4a8;\n$fa-var-austral-sign: \\e0a9;\n$fa-var-f: \\46;\n$fa-var-leaf: \\f06c;\n$fa-var-road: \\f018;\n$fa-var-taxi: \\f1ba;\n$fa-var-cab: \\f1ba;\n$fa-var-person-circle-plus: \\e541;\n$fa-var-chart-pie: \\f200;\n$fa-var-pie-chart: \\f200;\n$fa-var-bolt-lightning: \\e0b7;\n$fa-var-sack-xmark: \\e56a;\n$fa-var-file-excel: \\f1c3;\n$fa-var-file-contract: \\f56c;\n$fa-var-fish-fins: \\e4f2;\n$fa-var-building-flag: \\e4d5;\n$fa-var-face-grin-beam: \\f582;\n$fa-var-grin-beam: \\f582;\n$fa-var-object-ungroup: \\f248;\n$fa-var-poop: \\f619;\n$fa-var-location-pin: \\f041;\n$fa-var-map-marker: \\f041;\n$fa-var-kaaba: \\f66b;\n$fa-var-toilet-paper: \\f71e;\n$fa-var-helmet-safety: \\f807;\n$fa-var-hard-hat: \\f807;\n$fa-var-hat-hard: \\f807;\n$fa-var-eject: \\f052;\n$fa-var-circle-right: \\f35a;\n$fa-var-arrow-alt-circle-right: \\f35a;\n$fa-var-plane-circle-check: \\e555;\n$fa-var-face-rolling-eyes: \\f5a5;\n$fa-var-meh-rolling-eyes: \\f5a5;\n$fa-var-object-group: \\f247;\n$fa-var-chart-line: \\f201;\n$fa-var-line-chart: \\f201;\n$fa-var-mask-ventilator: \\e524;\n$fa-var-arrow-right: \\f061;\n$fa-var-signs-post: \\f277;\n$fa-var-map-signs: \\f277;\n$fa-var-cash-register: \\f788;\n$fa-var-person-circle-question: \\e542;\n$fa-var-h: \\48;\n$fa-var-tarp: \\e57b;\n$fa-var-screwdriver-wrench: \\f7d9;\n$fa-var-tools: \\f7d9;\n$fa-var-arrows-to-eye: \\e4bf;\n$fa-var-plug-circle-bolt: \\e55b;\n$fa-var-heart: \\f004;\n$fa-var-mars-and-venus: \\f224;\n$fa-var-house-user: \\e1b0;\n$fa-var-home-user: \\e1b0;\n$fa-var-dumpster-fire: \\f794;\n$fa-var-house-crack: \\e3b1;\n$fa-var-martini-glass-citrus: \\f561;\n$fa-var-cocktail: \\f561;\n$fa-var-face-surprise: \\f5c2;\n$fa-var-surprise: \\f5c2;\n$fa-var-bottle-water: \\e4c5;\n$fa-var-circle-pause: \\f28b;\n$fa-var-pause-circle: \\f28b;\n$fa-var-toilet-paper-slash: \\e072;\n$fa-var-apple-whole: \\f5d1;\n$fa-var-apple-alt: \\f5d1;\n$fa-var-kitchen-set: \\e51a;\n$fa-var-r: \\52;\n$fa-var-temperature-quarter: \\f2ca;\n$fa-var-temperature-1: \\f2ca;\n$fa-var-thermometer-1: \\f2ca;\n$fa-var-thermometer-quarter: \\f2ca;\n$fa-var-cube: \\f1b2;\n$fa-var-bitcoin-sign: \\e0b4;\n$fa-var-shield-dog: \\e573;\n$fa-var-solar-panel: \\f5ba;\n$fa-var-lock-open: \\f3c1;\n$fa-var-elevator: \\e16d;\n$fa-var-money-bill-transfer: \\e528;\n$fa-var-money-bill-trend-up: \\e529;\n$fa-var-house-flood-water-circle-arrow-right: \\e50f;\n$fa-var-square-poll-horizontal: \\f682;\n$fa-var-poll-h: \\f682;\n$fa-var-circle: \\f111;\n$fa-var-backward-fast: \\f049;\n$fa-var-fast-backward: \\f049;\n$fa-var-recycle: \\f1b8;\n$fa-var-user-astronaut: \\f4fb;\n$fa-var-plane-slash: \\e069;\n$fa-var-trademark: \\f25c;\n$fa-var-basketball: \\f434;\n$fa-var-basketball-ball: \\f434;\n$fa-var-satellite-dish: \\f7c0;\n$fa-var-circle-up: \\f35b;\n$fa-var-arrow-alt-circle-up: \\f35b;\n$fa-var-mobile-screen-button: \\f3cd;\n$fa-var-mobile-alt: \\f3cd;\n$fa-var-volume-high: \\f028;\n$fa-var-volume-up: \\f028;\n$fa-var-users-rays: \\e593;\n$fa-var-wallet: \\f555;\n$fa-var-clipboard-check: \\f46c;\n$fa-var-file-audio: \\f1c7;\n$fa-var-burger: \\f805;\n$fa-var-hamburger: \\f805;\n$fa-var-wrench: \\f0ad;\n$fa-var-bugs: \\e4d0;\n$fa-var-rupee-sign: \\f156;\n$fa-var-rupee: \\f156;\n$fa-var-file-image: \\f1c5;\n$fa-var-circle-question: \\f059;\n$fa-var-question-circle: \\f059;\n$fa-var-plane-departure: \\f5b0;\n$fa-var-handshake-slash: \\e060;\n$fa-var-book-bookmark: \\e0bb;\n$fa-var-code-branch: \\f126;\n$fa-var-hat-cowboy: \\f8c0;\n$fa-var-bridge: \\e4c8;\n$fa-var-phone-flip: \\f879;\n$fa-var-phone-alt: \\f879;\n$fa-var-truck-front: \\e2b7;\n$fa-var-cat: \\f6be;\n$fa-var-anchor-circle-exclamation: \\e4ab;\n$fa-var-truck-field: \\e58d;\n$fa-var-route: \\f4d7;\n$fa-var-clipboard-question: \\e4e3;\n$fa-var-panorama: \\e209;\n$fa-var-comment-medical: \\f7f5;\n$fa-var-teeth-open: \\f62f;\n$fa-var-file-circle-minus: \\e4ed;\n$fa-var-tags: \\f02c;\n$fa-var-wine-glass: \\f4e3;\n$fa-var-forward-fast: \\f050;\n$fa-var-fast-forward: \\f050;\n$fa-var-face-meh-blank: \\f5a4;\n$fa-var-meh-blank: \\f5a4;\n$fa-var-square-parking: \\f540;\n$fa-var-parking: \\f540;\n$fa-var-house-signal: \\e012;\n$fa-var-bars-progress: \\f828;\n$fa-var-tasks-alt: \\f828;\n$fa-var-faucet-drip: \\e006;\n$fa-var-cart-flatbed: \\f474;\n$fa-var-dolly-flatbed: \\f474;\n$fa-var-ban-smoking: \\f54d;\n$fa-var-smoking-ban: \\f54d;\n$fa-var-terminal: \\f120;\n$fa-var-mobile-button: \\f10b;\n$fa-var-house-medical-flag: \\e514;\n$fa-var-basket-shopping: \\f291;\n$fa-var-shopping-basket: \\f291;\n$fa-var-tape: \\f4db;\n$fa-var-bus-simple: \\f55e;\n$fa-var-bus-alt: \\f55e;\n$fa-var-eye: \\f06e;\n$fa-var-face-sad-cry: \\f5b3;\n$fa-var-sad-cry: \\f5b3;\n$fa-var-audio-description: \\f29e;\n$fa-var-person-military-to-person: \\e54c;\n$fa-var-file-shield: \\e4f0;\n$fa-var-user-slash: \\f506;\n$fa-var-pen: \\f304;\n$fa-var-tower-observation: \\e586;\n$fa-var-file-code: \\f1c9;\n$fa-var-signal: \\f012;\n$fa-var-signal-5: \\f012;\n$fa-var-signal-perfect: \\f012;\n$fa-var-bus: \\f207;\n$fa-var-heart-circle-xmark: \\e501;\n$fa-var-house-chimney: \\e3af;\n$fa-var-home-lg: \\e3af;\n$fa-var-window-maximize: \\f2d0;\n$fa-var-face-frown: \\f119;\n$fa-var-frown: \\f119;\n$fa-var-prescription: \\f5b1;\n$fa-var-shop: \\f54f;\n$fa-var-store-alt: \\f54f;\n$fa-var-floppy-disk: \\f0c7;\n$fa-var-save: \\f0c7;\n$fa-var-vihara: \\f6a7;\n$fa-var-scale-unbalanced: \\f515;\n$fa-var-balance-scale-left: \\f515;\n$fa-var-sort-up: \\f0de;\n$fa-var-sort-asc: \\f0de;\n$fa-var-comment-dots: \\f4ad;\n$fa-var-commenting: \\f4ad;\n$fa-var-plant-wilt: \\e5aa;\n$fa-var-diamond: \\f219;\n$fa-var-face-grin-squint: \\f585;\n$fa-var-grin-squint: \\f585;\n$fa-var-hand-holding-dollar: \\f4c0;\n$fa-var-hand-holding-usd: \\f4c0;\n$fa-var-chart-diagram: \\e695;\n$fa-var-bacterium: \\e05a;\n$fa-var-hand-pointer: \\f25a;\n$fa-var-drum-steelpan: \\f56a;\n$fa-var-hand-scissors: \\f257;\n$fa-var-hands-praying: \\f684;\n$fa-var-praying-hands: \\f684;\n$fa-var-arrow-rotate-right: \\f01e;\n$fa-var-arrow-right-rotate: \\f01e;\n$fa-var-arrow-rotate-forward: \\f01e;\n$fa-var-redo: \\f01e;\n$fa-var-biohazard: \\f780;\n$fa-var-location-crosshairs: \\f601;\n$fa-var-location: \\f601;\n$fa-var-mars-double: \\f227;\n$fa-var-child-dress: \\e59c;\n$fa-var-users-between-lines: \\e591;\n$fa-var-lungs-virus: \\e067;\n$fa-var-face-grin-tears: \\f588;\n$fa-var-grin-tears: \\f588;\n$fa-var-phone: \\f095;\n$fa-var-calendar-xmark: \\f273;\n$fa-var-calendar-times: \\f273;\n$fa-var-child-reaching: \\e59d;\n$fa-var-head-side-virus: \\e064;\n$fa-var-user-gear: \\f4fe;\n$fa-var-user-cog: \\f4fe;\n$fa-var-arrow-up-1-9: \\f163;\n$fa-var-sort-numeric-up: \\f163;\n$fa-var-door-closed: \\f52a;\n$fa-var-shield-virus: \\e06c;\n$fa-var-dice-six: \\f526;\n$fa-var-mosquito-net: \\e52c;\n$fa-var-file-fragment: \\e697;\n$fa-var-bridge-water: \\e4ce;\n$fa-var-person-booth: \\f756;\n$fa-var-text-width: \\f035;\n$fa-var-hat-wizard: \\f6e8;\n$fa-var-pen-fancy: \\f5ac;\n$fa-var-person-digging: \\f85e;\n$fa-var-digging: \\f85e;\n$fa-var-trash: \\f1f8;\n$fa-var-gauge-simple: \\f629;\n$fa-var-gauge-simple-med: \\f629;\n$fa-var-tachometer-average: \\f629;\n$fa-var-book-medical: \\f7e6;\n$fa-var-poo: \\f2fe;\n$fa-var-quote-right: \\f10e;\n$fa-var-quote-right-alt: \\f10e;\n$fa-var-shirt: \\f553;\n$fa-var-t-shirt: \\f553;\n$fa-var-tshirt: \\f553;\n$fa-var-cubes: \\f1b3;\n$fa-var-divide: \\f529;\n$fa-var-tenge-sign: \\f7d7;\n$fa-var-tenge: \\f7d7;\n$fa-var-headphones: \\f025;\n$fa-var-hands-holding: \\f4c2;\n$fa-var-hands-clapping: \\e1a8;\n$fa-var-republican: \\f75e;\n$fa-var-arrow-left: \\f060;\n$fa-var-person-circle-xmark: \\e543;\n$fa-var-ruler: \\f545;\n$fa-var-align-left: \\f036;\n$fa-var-dice-d6: \\f6d1;\n$fa-var-restroom: \\f7bd;\n$fa-var-j: \\4a;\n$fa-var-users-viewfinder: \\e595;\n$fa-var-file-video: \\f1c8;\n$fa-var-up-right-from-square: \\f35d;\n$fa-var-external-link-alt: \\f35d;\n$fa-var-table-cells: \\f00a;\n$fa-var-th: \\f00a;\n$fa-var-file-pdf: \\f1c1;\n$fa-var-book-bible: \\f647;\n$fa-var-bible: \\f647;\n$fa-var-o: \\4f;\n$fa-var-suitcase-medical: \\f0fa;\n$fa-var-medkit: \\f0fa;\n$fa-var-user-secret: \\f21b;\n$fa-var-otter: \\f700;\n$fa-var-person-dress: \\f182;\n$fa-var-female: \\f182;\n$fa-var-comment-dollar: \\f651;\n$fa-var-business-time: \\f64a;\n$fa-var-briefcase-clock: \\f64a;\n$fa-var-table-cells-large: \\f009;\n$fa-var-th-large: \\f009;\n$fa-var-book-tanakh: \\f827;\n$fa-var-tanakh: \\f827;\n$fa-var-phone-volume: \\f2a0;\n$fa-var-volume-control-phone: \\f2a0;\n$fa-var-hat-cowboy-side: \\f8c1;\n$fa-var-clipboard-user: \\f7f3;\n$fa-var-child: \\f1ae;\n$fa-var-lira-sign: \\f195;\n$fa-var-satellite: \\f7bf;\n$fa-var-plane-lock: \\e558;\n$fa-var-tag: \\f02b;\n$fa-var-comment: \\f075;\n$fa-var-cake-candles: \\f1fd;\n$fa-var-birthday-cake: \\f1fd;\n$fa-var-cake: \\f1fd;\n$fa-var-envelope: \\f0e0;\n$fa-var-angles-up: \\f102;\n$fa-var-angle-double-up: \\f102;\n$fa-var-paperclip: \\f0c6;\n$fa-var-arrow-right-to-city: \\e4b3;\n$fa-var-ribbon: \\f4d6;\n$fa-var-lungs: \\f604;\n$fa-var-arrow-up-9-1: \\f887;\n$fa-var-sort-numeric-up-alt: \\f887;\n$fa-var-litecoin-sign: \\e1d3;\n$fa-var-border-none: \\f850;\n$fa-var-circle-nodes: \\e4e2;\n$fa-var-parachute-box: \\f4cd;\n$fa-var-indent: \\f03c;\n$fa-var-truck-field-un: \\e58e;\n$fa-var-hourglass: \\f254;\n$fa-var-hourglass-empty: \\f254;\n$fa-var-mountain: \\f6fc;\n$fa-var-user-doctor: \\f0f0;\n$fa-var-user-md: \\f0f0;\n$fa-var-circle-info: \\f05a;\n$fa-var-info-circle: \\f05a;\n$fa-var-cloud-meatball: \\f73b;\n$fa-var-camera: \\f030;\n$fa-var-camera-alt: \\f030;\n$fa-var-square-virus: \\e578;\n$fa-var-meteor: \\f753;\n$fa-var-car-on: \\e4dd;\n$fa-var-sleigh: \\f7cc;\n$fa-var-arrow-down-1-9: \\f162;\n$fa-var-sort-numeric-asc: \\f162;\n$fa-var-sort-numeric-down: \\f162;\n$fa-var-hand-holding-droplet: \\f4c1;\n$fa-var-hand-holding-water: \\f4c1;\n$fa-var-water: \\f773;\n$fa-var-calendar-check: \\f274;\n$fa-var-braille: \\f2a1;\n$fa-var-prescription-bottle-medical: \\f486;\n$fa-var-prescription-bottle-alt: \\f486;\n$fa-var-landmark: \\f66f;\n$fa-var-truck: \\f0d1;\n$fa-var-crosshairs: \\f05b;\n$fa-var-person-cane: \\e53c;\n$fa-var-tent: \\e57d;\n$fa-var-vest-patches: \\e086;\n$fa-var-check-double: \\f560;\n$fa-var-arrow-down-a-z: \\f15d;\n$fa-var-sort-alpha-asc: \\f15d;\n$fa-var-sort-alpha-down: \\f15d;\n$fa-var-money-bill-wheat: \\e52a;\n$fa-var-cookie: \\f563;\n$fa-var-arrow-rotate-left: \\f0e2;\n$fa-var-arrow-left-rotate: \\f0e2;\n$fa-var-arrow-rotate-back: \\f0e2;\n$fa-var-arrow-rotate-backward: \\f0e2;\n$fa-var-undo: \\f0e2;\n$fa-var-hard-drive: \\f0a0;\n$fa-var-hdd: \\f0a0;\n$fa-var-face-grin-squint-tears: \\f586;\n$fa-var-grin-squint-tears: \\f586;\n$fa-var-dumbbell: \\f44b;\n$fa-var-rectangle-list: \\f022;\n$fa-var-list-alt: \\f022;\n$fa-var-tarp-droplet: \\e57c;\n$fa-var-house-medical-circle-check: \\e511;\n$fa-var-person-skiing-nordic: \\f7ca;\n$fa-var-skiing-nordic: \\f7ca;\n$fa-var-calendar-plus: \\f271;\n$fa-var-plane-arrival: \\f5af;\n$fa-var-circle-left: \\f359;\n$fa-var-arrow-alt-circle-left: \\f359;\n$fa-var-train-subway: \\f239;\n$fa-var-subway: \\f239;\n$fa-var-chart-gantt: \\e0e4;\n$fa-var-indian-rupee-sign: \\e1bc;\n$fa-var-indian-rupee: \\e1bc;\n$fa-var-inr: \\e1bc;\n$fa-var-crop-simple: \\f565;\n$fa-var-crop-alt: \\f565;\n$fa-var-money-bill-1: \\f3d1;\n$fa-var-money-bill-alt: \\f3d1;\n$fa-var-left-long: \\f30a;\n$fa-var-long-arrow-alt-left: \\f30a;\n$fa-var-dna: \\f471;\n$fa-var-virus-slash: \\e075;\n$fa-var-minus: \\f068;\n$fa-var-subtract: \\f068;\n$fa-var-chess: \\f439;\n$fa-var-arrow-left-long: \\f177;\n$fa-var-long-arrow-left: \\f177;\n$fa-var-plug-circle-check: \\e55c;\n$fa-var-street-view: \\f21d;\n$fa-var-franc-sign: \\e18f;\n$fa-var-volume-off: \\f026;\n$fa-var-hands-asl-interpreting: \\f2a3;\n$fa-var-american-sign-language-interpreting: \\f2a3;\n$fa-var-asl-interpreting: \\f2a3;\n$fa-var-hands-american-sign-language-interpreting: \\f2a3;\n$fa-var-gear: \\f013;\n$fa-var-cog: \\f013;\n$fa-var-droplet-slash: \\f5c7;\n$fa-var-tint-slash: \\f5c7;\n$fa-var-mosque: \\f678;\n$fa-var-mosquito: \\e52b;\n$fa-var-star-of-david: \\f69a;\n$fa-var-person-military-rifle: \\e54b;\n$fa-var-cart-shopping: \\f07a;\n$fa-var-shopping-cart: \\f07a;\n$fa-var-vials: \\f493;\n$fa-var-plug-circle-plus: \\e55f;\n$fa-var-place-of-worship: \\f67f;\n$fa-var-grip-vertical: \\f58e;\n$fa-var-hexagon-nodes: \\e699;\n$fa-var-arrow-turn-up: \\f148;\n$fa-var-level-up: \\f148;\n$fa-var-u: \\55;\n$fa-var-square-root-variable: \\f698;\n$fa-var-square-root-alt: \\f698;\n$fa-var-clock: \\f017;\n$fa-var-clock-four: \\f017;\n$fa-var-backward-step: \\f048;\n$fa-var-step-backward: \\f048;\n$fa-var-pallet: \\f482;\n$fa-var-faucet: \\e005;\n$fa-var-baseball-bat-ball: \\f432;\n$fa-var-s: \\53;\n$fa-var-timeline: \\e29c;\n$fa-var-keyboard: \\f11c;\n$fa-var-caret-down: \\f0d7;\n$fa-var-house-chimney-medical: \\f7f2;\n$fa-var-clinic-medical: \\f7f2;\n$fa-var-temperature-three-quarters: \\f2c8;\n$fa-var-temperature-3: \\f2c8;\n$fa-var-thermometer-3: \\f2c8;\n$fa-var-thermometer-three-quarters: \\f2c8;\n$fa-var-mobile-screen: \\f3cf;\n$fa-var-mobile-android-alt: \\f3cf;\n$fa-var-plane-up: \\e22d;\n$fa-var-piggy-bank: \\f4d3;\n$fa-var-battery-half: \\f242;\n$fa-var-battery-3: \\f242;\n$fa-var-mountain-city: \\e52e;\n$fa-var-coins: \\f51e;\n$fa-var-khanda: \\f66d;\n$fa-var-sliders: \\f1de;\n$fa-var-sliders-h: \\f1de;\n$fa-var-folder-tree: \\f802;\n$fa-var-network-wired: \\f6ff;\n$fa-var-map-pin: \\f276;\n$fa-var-hamsa: \\f665;\n$fa-var-cent-sign: \\e3f5;\n$fa-var-flask: \\f0c3;\n$fa-var-person-pregnant: \\e31e;\n$fa-var-wand-sparkles: \\f72b;\n$fa-var-ellipsis-vertical: \\f142;\n$fa-var-ellipsis-v: \\f142;\n$fa-var-ticket: \\f145;\n$fa-var-power-off: \\f011;\n$fa-var-right-long: \\f30b;\n$fa-var-long-arrow-alt-right: \\f30b;\n$fa-var-flag-usa: \\f74d;\n$fa-var-laptop-file: \\e51d;\n$fa-var-tty: \\f1e4;\n$fa-var-teletype: \\f1e4;\n$fa-var-diagram-next: \\e476;\n$fa-var-person-rifle: \\e54e;\n$fa-var-house-medical-circle-exclamation: \\e512;\n$fa-var-closed-captioning: \\f20a;\n$fa-var-person-hiking: \\f6ec;\n$fa-var-hiking: \\f6ec;\n$fa-var-venus-double: \\f226;\n$fa-var-images: \\f302;\n$fa-var-calculator: \\f1ec;\n$fa-var-people-pulling: \\e535;\n$fa-var-n: \\4e;\n$fa-var-cable-car: \\f7da;\n$fa-var-tram: \\f7da;\n$fa-var-cloud-rain: \\f73d;\n$fa-var-building-circle-xmark: \\e4d4;\n$fa-var-ship: \\f21a;\n$fa-var-arrows-down-to-line: \\e4b8;\n$fa-var-download: \\f019;\n$fa-var-face-grin: \\f580;\n$fa-var-grin: \\f580;\n$fa-var-delete-left: \\f55a;\n$fa-var-backspace: \\f55a;\n$fa-var-eye-dropper: \\f1fb;\n$fa-var-eye-dropper-empty: \\f1fb;\n$fa-var-eyedropper: \\f1fb;\n$fa-var-file-circle-check: \\e5a0;\n$fa-var-forward: \\f04e;\n$fa-var-mobile: \\f3ce;\n$fa-var-mobile-android: \\f3ce;\n$fa-var-mobile-phone: \\f3ce;\n$fa-var-face-meh: \\f11a;\n$fa-var-meh: \\f11a;\n$fa-var-align-center: \\f037;\n$fa-var-book-skull: \\f6b7;\n$fa-var-book-dead: \\f6b7;\n$fa-var-id-card: \\f2c2;\n$fa-var-drivers-license: \\f2c2;\n$fa-var-outdent: \\f03b;\n$fa-var-dedent: \\f03b;\n$fa-var-heart-circle-exclamation: \\e4fe;\n$fa-var-house: \\f015;\n$fa-var-home: \\f015;\n$fa-var-home-alt: \\f015;\n$fa-var-home-lg-alt: \\f015;\n$fa-var-calendar-week: \\f784;\n$fa-var-laptop-medical: \\f812;\n$fa-var-b: \\42;\n$fa-var-file-medical: \\f477;\n$fa-var-dice-one: \\f525;\n$fa-var-kiwi-bird: \\f535;\n$fa-var-arrow-right-arrow-left: \\f0ec;\n$fa-var-exchange: \\f0ec;\n$fa-var-rotate-right: \\f2f9;\n$fa-var-redo-alt: \\f2f9;\n$fa-var-rotate-forward: \\f2f9;\n$fa-var-utensils: \\f2e7;\n$fa-var-cutlery: \\f2e7;\n$fa-var-arrow-up-wide-short: \\f161;\n$fa-var-sort-amount-up: \\f161;\n$fa-var-mill-sign: \\e1ed;\n$fa-var-bowl-rice: \\e2eb;\n$fa-var-skull: \\f54c;\n$fa-var-tower-broadcast: \\f519;\n$fa-var-broadcast-tower: \\f519;\n$fa-var-truck-pickup: \\f63c;\n$fa-var-up-long: \\f30c;\n$fa-var-long-arrow-alt-up: \\f30c;\n$fa-var-stop: \\f04d;\n$fa-var-code-merge: \\f387;\n$fa-var-upload: \\f093;\n$fa-var-hurricane: \\f751;\n$fa-var-mound: \\e52d;\n$fa-var-toilet-portable: \\e583;\n$fa-var-compact-disc: \\f51f;\n$fa-var-file-arrow-down: \\f56d;\n$fa-var-file-download: \\f56d;\n$fa-var-caravan: \\f8ff;\n$fa-var-shield-cat: \\e572;\n$fa-var-bolt: \\f0e7;\n$fa-var-zap: \\f0e7;\n$fa-var-glass-water: \\e4f4;\n$fa-var-oil-well: \\e532;\n$fa-var-vault: \\e2c5;\n$fa-var-mars: \\f222;\n$fa-var-toilet: \\f7d8;\n$fa-var-plane-circle-xmark: \\e557;\n$fa-var-yen-sign: \\f157;\n$fa-var-cny: \\f157;\n$fa-var-jpy: \\f157;\n$fa-var-rmb: \\f157;\n$fa-var-yen: \\f157;\n$fa-var-ruble-sign: \\f158;\n$fa-var-rouble: \\f158;\n$fa-var-rub: \\f158;\n$fa-var-ruble: \\f158;\n$fa-var-sun: \\f185;\n$fa-var-guitar: \\f7a6;\n$fa-var-face-laugh-wink: \\f59c;\n$fa-var-laugh-wink: \\f59c;\n$fa-var-horse-head: \\f7ab;\n$fa-var-bore-hole: \\e4c3;\n$fa-var-industry: \\f275;\n$fa-var-circle-down: \\f358;\n$fa-var-arrow-alt-circle-down: \\f358;\n$fa-var-arrows-turn-to-dots: \\e4c1;\n$fa-var-florin-sign: \\e184;\n$fa-var-arrow-down-short-wide: \\f884;\n$fa-var-sort-amount-desc: \\f884;\n$fa-var-sort-amount-down-alt: \\f884;\n$fa-var-less-than: \\3c;\n$fa-var-angle-down: \\f107;\n$fa-var-car-tunnel: \\e4de;\n$fa-var-head-side-cough: \\e061;\n$fa-var-grip-lines: \\f7a4;\n$fa-var-thumbs-down: \\f165;\n$fa-var-user-lock: \\f502;\n$fa-var-arrow-right-long: \\f178;\n$fa-var-long-arrow-right: \\f178;\n$fa-var-anchor-circle-xmark: \\e4ac;\n$fa-var-ellipsis: \\f141;\n$fa-var-ellipsis-h: \\f141;\n$fa-var-chess-pawn: \\f443;\n$fa-var-kit-medical: \\f479;\n$fa-var-first-aid: \\f479;\n$fa-var-person-through-window: \\e5a9;\n$fa-var-toolbox: \\f552;\n$fa-var-hands-holding-circle: \\e4fb;\n$fa-var-bug: \\f188;\n$fa-var-credit-card: \\f09d;\n$fa-var-credit-card-alt: \\f09d;\n$fa-var-car: \\f1b9;\n$fa-var-automobile: \\f1b9;\n$fa-var-hand-holding-hand: \\e4f7;\n$fa-var-book-open-reader: \\f5da;\n$fa-var-book-reader: \\f5da;\n$fa-var-mountain-sun: \\e52f;\n$fa-var-arrows-left-right-to-line: \\e4ba;\n$fa-var-dice-d20: \\f6cf;\n$fa-var-truck-droplet: \\e58c;\n$fa-var-file-circle-xmark: \\e5a1;\n$fa-var-temperature-arrow-up: \\e040;\n$fa-var-temperature-up: \\e040;\n$fa-var-medal: \\f5a2;\n$fa-var-bed: \\f236;\n$fa-var-square-h: \\f0fd;\n$fa-var-h-square: \\f0fd;\n$fa-var-podcast: \\f2ce;\n$fa-var-temperature-full: \\f2c7;\n$fa-var-temperature-4: \\f2c7;\n$fa-var-thermometer-4: \\f2c7;\n$fa-var-thermometer-full: \\f2c7;\n$fa-var-bell: \\f0f3;\n$fa-var-superscript: \\f12b;\n$fa-var-plug-circle-xmark: \\e560;\n$fa-var-star-of-life: \\f621;\n$fa-var-phone-slash: \\f3dd;\n$fa-var-paint-roller: \\f5aa;\n$fa-var-handshake-angle: \\f4c4;\n$fa-var-hands-helping: \\f4c4;\n$fa-var-location-dot: \\f3c5;\n$fa-var-map-marker-alt: \\f3c5;\n$fa-var-file: \\f15b;\n$fa-var-greater-than: \\3e;\n$fa-var-person-swimming: \\f5c4;\n$fa-var-swimmer: \\f5c4;\n$fa-var-arrow-down: \\f063;\n$fa-var-droplet: \\f043;\n$fa-var-tint: \\f043;\n$fa-var-eraser: \\f12d;\n$fa-var-earth-americas: \\f57d;\n$fa-var-earth: \\f57d;\n$fa-var-earth-america: \\f57d;\n$fa-var-globe-americas: \\f57d;\n$fa-var-person-burst: \\e53b;\n$fa-var-dove: \\f4ba;\n$fa-var-battery-empty: \\f244;\n$fa-var-battery-0: \\f244;\n$fa-var-socks: \\f696;\n$fa-var-inbox: \\f01c;\n$fa-var-section: \\e447;\n$fa-var-gauge-high: \\f625;\n$fa-var-tachometer-alt: \\f625;\n$fa-var-tachometer-alt-fast: \\f625;\n$fa-var-envelope-open-text: \\f658;\n$fa-var-hospital: \\f0f8;\n$fa-var-hospital-alt: \\f0f8;\n$fa-var-hospital-wide: \\f0f8;\n$fa-var-wine-bottle: \\f72f;\n$fa-var-chess-rook: \\f447;\n$fa-var-bars-staggered: \\f550;\n$fa-var-reorder: \\f550;\n$fa-var-stream: \\f550;\n$fa-var-dharmachakra: \\f655;\n$fa-var-hotdog: \\f80f;\n$fa-var-person-walking-with-cane: \\f29d;\n$fa-var-blind: \\f29d;\n$fa-var-drum: \\f569;\n$fa-var-ice-cream: \\f810;\n$fa-var-heart-circle-bolt: \\e4fc;\n$fa-var-fax: \\f1ac;\n$fa-var-paragraph: \\f1dd;\n$fa-var-check-to-slot: \\f772;\n$fa-var-vote-yea: \\f772;\n$fa-var-star-half: \\f089;\n$fa-var-boxes-stacked: \\f468;\n$fa-var-boxes: \\f468;\n$fa-var-boxes-alt: \\f468;\n$fa-var-link: \\f0c1;\n$fa-var-chain: \\f0c1;\n$fa-var-ear-listen: \\f2a2;\n$fa-var-assistive-listening-systems: \\f2a2;\n$fa-var-tree-city: \\e587;\n$fa-var-play: \\f04b;\n$fa-var-font: \\f031;\n$fa-var-table-cells-row-lock: \\e67a;\n$fa-var-rupiah-sign: \\e23d;\n$fa-var-magnifying-glass: \\f002;\n$fa-var-search: \\f002;\n$fa-var-table-tennis-paddle-ball: \\f45d;\n$fa-var-ping-pong-paddle-ball: \\f45d;\n$fa-var-table-tennis: \\f45d;\n$fa-var-person-dots-from-line: \\f470;\n$fa-var-diagnoses: \\f470;\n$fa-var-trash-can-arrow-up: \\f82a;\n$fa-var-trash-restore-alt: \\f82a;\n$fa-var-naira-sign: \\e1f6;\n$fa-var-cart-arrow-down: \\f218;\n$fa-var-walkie-talkie: \\f8ef;\n$fa-var-file-pen: \\f31c;\n$fa-var-file-edit: \\f31c;\n$fa-var-receipt: \\f543;\n$fa-var-square-pen: \\f14b;\n$fa-var-pen-square: \\f14b;\n$fa-var-pencil-square: \\f14b;\n$fa-var-suitcase-rolling: \\f5c1;\n$fa-var-person-circle-exclamation: \\e53f;\n$fa-var-chevron-down: \\f078;\n$fa-var-battery-full: \\f240;\n$fa-var-battery: \\f240;\n$fa-var-battery-5: \\f240;\n$fa-var-skull-crossbones: \\f714;\n$fa-var-code-compare: \\e13a;\n$fa-var-list-ul: \\f0ca;\n$fa-var-list-dots: \\f0ca;\n$fa-var-school-lock: \\e56f;\n$fa-var-tower-cell: \\e585;\n$fa-var-down-long: \\f309;\n$fa-var-long-arrow-alt-down: \\f309;\n$fa-var-ranking-star: \\e561;\n$fa-var-chess-king: \\f43f;\n$fa-var-person-harassing: \\e549;\n$fa-var-brazilian-real-sign: \\e46c;\n$fa-var-landmark-dome: \\f752;\n$fa-var-landmark-alt: \\f752;\n$fa-var-arrow-up: \\f062;\n$fa-var-tv: \\f26c;\n$fa-var-television: \\f26c;\n$fa-var-tv-alt: \\f26c;\n$fa-var-shrimp: \\e448;\n$fa-var-list-check: \\f0ae;\n$fa-var-tasks: \\f0ae;\n$fa-var-jug-detergent: \\e519;\n$fa-var-circle-user: \\f2bd;\n$fa-var-user-circle: \\f2bd;\n$fa-var-user-shield: \\f505;\n$fa-var-wind: \\f72e;\n$fa-var-car-burst: \\f5e1;\n$fa-var-car-crash: \\f5e1;\n$fa-var-y: \\59;\n$fa-var-person-snowboarding: \\f7ce;\n$fa-var-snowboarding: \\f7ce;\n$fa-var-truck-fast: \\f48b;\n$fa-var-shipping-fast: \\f48b;\n$fa-var-fish: \\f578;\n$fa-var-user-graduate: \\f501;\n$fa-var-circle-half-stroke: \\f042;\n$fa-var-adjust: \\f042;\n$fa-var-clapperboard: \\e131;\n$fa-var-circle-radiation: \\f7ba;\n$fa-var-radiation-alt: \\f7ba;\n$fa-var-baseball: \\f433;\n$fa-var-baseball-ball: \\f433;\n$fa-var-jet-fighter-up: \\e518;\n$fa-var-diagram-project: \\f542;\n$fa-var-project-diagram: \\f542;\n$fa-var-copy: \\f0c5;\n$fa-var-volume-xmark: \\f6a9;\n$fa-var-volume-mute: \\f6a9;\n$fa-var-volume-times: \\f6a9;\n$fa-var-hand-sparkles: \\e05d;\n$fa-var-grip: \\f58d;\n$fa-var-grip-horizontal: \\f58d;\n$fa-var-share-from-square: \\f14d;\n$fa-var-share-square: \\f14d;\n$fa-var-child-combatant: \\e4e0;\n$fa-var-child-rifle: \\e4e0;\n$fa-var-gun: \\e19b;\n$fa-var-square-phone: \\f098;\n$fa-var-phone-square: \\f098;\n$fa-var-plus: \\2b;\n$fa-var-add: \\2b;\n$fa-var-expand: \\f065;\n$fa-var-computer: \\e4e5;\n$fa-var-xmark: \\f00d;\n$fa-var-close: \\f00d;\n$fa-var-multiply: \\f00d;\n$fa-var-remove: \\f00d;\n$fa-var-times: \\f00d;\n$fa-var-arrows-up-down-left-right: \\f047;\n$fa-var-arrows: \\f047;\n$fa-var-chalkboard-user: \\f51c;\n$fa-var-chalkboard-teacher: \\f51c;\n$fa-var-peso-sign: \\e222;\n$fa-var-building-shield: \\e4d8;\n$fa-var-baby: \\f77c;\n$fa-var-users-line: \\e592;\n$fa-var-quote-left: \\f10d;\n$fa-var-quote-left-alt: \\f10d;\n$fa-var-tractor: \\f722;\n$fa-var-trash-arrow-up: \\f829;\n$fa-var-trash-restore: \\f829;\n$fa-var-arrow-down-up-lock: \\e4b0;\n$fa-var-lines-leaning: \\e51e;\n$fa-var-ruler-combined: \\f546;\n$fa-var-copyright: \\f1f9;\n$fa-var-equals: \\3d;\n$fa-var-blender: \\f517;\n$fa-var-teeth: \\f62e;\n$fa-var-shekel-sign: \\f20b;\n$fa-var-ils: \\f20b;\n$fa-var-shekel: \\f20b;\n$fa-var-sheqel: \\f20b;\n$fa-var-sheqel-sign: \\f20b;\n$fa-var-map: \\f279;\n$fa-var-rocket: \\f135;\n$fa-var-photo-film: \\f87c;\n$fa-var-photo-video: \\f87c;\n$fa-var-folder-minus: \\f65d;\n$fa-var-hexagon-nodes-bolt: \\e69a;\n$fa-var-store: \\f54e;\n$fa-var-arrow-trend-up: \\e098;\n$fa-var-plug-circle-minus: \\e55e;\n$fa-var-sign-hanging: \\f4d9;\n$fa-var-sign: \\f4d9;\n$fa-var-bezier-curve: \\f55b;\n$fa-var-bell-slash: \\f1f6;\n$fa-var-tablet: \\f3fb;\n$fa-var-tablet-android: \\f3fb;\n$fa-var-school-flag: \\e56e;\n$fa-var-fill: \\f575;\n$fa-var-angle-up: \\f106;\n$fa-var-drumstick-bite: \\f6d7;\n$fa-var-holly-berry: \\f7aa;\n$fa-var-chevron-left: \\f053;\n$fa-var-bacteria: \\e059;\n$fa-var-hand-lizard: \\f258;\n$fa-var-notdef: \\e1fe;\n$fa-var-disease: \\f7fa;\n$fa-var-briefcase-medical: \\f469;\n$fa-var-genderless: \\f22d;\n$fa-var-chevron-right: \\f054;\n$fa-var-retweet: \\f079;\n$fa-var-car-rear: \\f5de;\n$fa-var-car-alt: \\f5de;\n$fa-var-pump-soap: \\e06b;\n$fa-var-video-slash: \\f4e2;\n$fa-var-battery-quarter: \\f243;\n$fa-var-battery-2: \\f243;\n$fa-var-radio: \\f8d7;\n$fa-var-baby-carriage: \\f77d;\n$fa-var-carriage-baby: \\f77d;\n$fa-var-traffic-light: \\f637;\n$fa-var-thermometer: \\f491;\n$fa-var-vr-cardboard: \\f729;\n$fa-var-hand-middle-finger: \\f806;\n$fa-var-percent: \\25;\n$fa-var-percentage: \\25;\n$fa-var-truck-moving: \\f4df;\n$fa-var-glass-water-droplet: \\e4f5;\n$fa-var-display: \\e163;\n$fa-var-face-smile: \\f118;\n$fa-var-smile: \\f118;\n$fa-var-thumbtack: \\f08d;\n$fa-var-thumb-tack: \\f08d;\n$fa-var-trophy: \\f091;\n$fa-var-person-praying: \\f683;\n$fa-var-pray: \\f683;\n$fa-var-hammer: \\f6e3;\n$fa-var-hand-peace: \\f25b;\n$fa-var-rotate: \\f2f1;\n$fa-var-sync-alt: \\f2f1;\n$fa-var-spinner: \\f110;\n$fa-var-robot: \\f544;\n$fa-var-peace: \\f67c;\n$fa-var-gears: \\f085;\n$fa-var-cogs: \\f085;\n$fa-var-warehouse: \\f494;\n$fa-var-arrow-up-right-dots: \\e4b7;\n$fa-var-splotch: \\f5bc;\n$fa-var-face-grin-hearts: \\f584;\n$fa-var-grin-hearts: \\f584;\n$fa-var-dice-four: \\f524;\n$fa-var-sim-card: \\f7c4;\n$fa-var-transgender: \\f225;\n$fa-var-transgender-alt: \\f225;\n$fa-var-mercury: \\f223;\n$fa-var-arrow-turn-down: \\f149;\n$fa-var-level-down: \\f149;\n$fa-var-person-falling-burst: \\e547;\n$fa-var-award: \\f559;\n$fa-var-ticket-simple: \\f3ff;\n$fa-var-ticket-alt: \\f3ff;\n$fa-var-building: \\f1ad;\n$fa-var-angles-left: \\f100;\n$fa-var-angle-double-left: \\f100;\n$fa-var-qrcode: \\f029;\n$fa-var-clock-rotate-left: \\f1da;\n$fa-var-history: \\f1da;\n$fa-var-face-grin-beam-sweat: \\f583;\n$fa-var-grin-beam-sweat: \\f583;\n$fa-var-file-export: \\f56e;\n$fa-var-arrow-right-from-file: \\f56e;\n$fa-var-shield: \\f132;\n$fa-var-shield-blank: \\f132;\n$fa-var-arrow-up-short-wide: \\f885;\n$fa-var-sort-amount-up-alt: \\f885;\n$fa-var-comment-nodes: \\e696;\n$fa-var-house-medical: \\e3b2;\n$fa-var-golf-ball-tee: \\f450;\n$fa-var-golf-ball: \\f450;\n$fa-var-circle-chevron-left: \\f137;\n$fa-var-chevron-circle-left: \\f137;\n$fa-var-house-chimney-window: \\e00d;\n$fa-var-pen-nib: \\f5ad;\n$fa-var-tent-arrow-turn-left: \\e580;\n$fa-var-tents: \\e582;\n$fa-var-wand-magic: \\f0d0;\n$fa-var-magic: \\f0d0;\n$fa-var-dog: \\f6d3;\n$fa-var-carrot: \\f787;\n$fa-var-moon: \\f186;\n$fa-var-wine-glass-empty: \\f5ce;\n$fa-var-wine-glass-alt: \\f5ce;\n$fa-var-cheese: \\f7ef;\n$fa-var-yin-yang: \\f6ad;\n$fa-var-music: \\f001;\n$fa-var-code-commit: \\f386;\n$fa-var-temperature-low: \\f76b;\n$fa-var-person-biking: \\f84a;\n$fa-var-biking: \\f84a;\n$fa-var-broom: \\f51a;\n$fa-var-shield-heart: \\e574;\n$fa-var-gopuram: \\f664;\n$fa-var-earth-oceania: \\e47b;\n$fa-var-globe-oceania: \\e47b;\n$fa-var-square-xmark: \\f2d3;\n$fa-var-times-square: \\f2d3;\n$fa-var-xmark-square: \\f2d3;\n$fa-var-hashtag: \\23;\n$fa-var-up-right-and-down-left-from-center: \\f424;\n$fa-var-expand-alt: \\f424;\n$fa-var-oil-can: \\f613;\n$fa-var-t: \\54;\n$fa-var-hippo: \\f6ed;\n$fa-var-chart-column: \\e0e3;\n$fa-var-infinity: \\f534;\n$fa-var-vial-circle-check: \\e596;\n$fa-var-person-arrow-down-to-line: \\e538;\n$fa-var-voicemail: \\f897;\n$fa-var-fan: \\f863;\n$fa-var-person-walking-luggage: \\e554;\n$fa-var-up-down: \\f338;\n$fa-var-arrows-alt-v: \\f338;\n$fa-var-cloud-moon-rain: \\f73c;\n$fa-var-calendar: \\f133;\n$fa-var-trailer: \\e041;\n$fa-var-bahai: \\f666;\n$fa-var-haykal: \\f666;\n$fa-var-sd-card: \\f7c2;\n$fa-var-dragon: \\f6d5;\n$fa-var-shoe-prints: \\f54b;\n$fa-var-circle-plus: \\f055;\n$fa-var-plus-circle: \\f055;\n$fa-var-face-grin-tongue-wink: \\f58b;\n$fa-var-grin-tongue-wink: \\f58b;\n$fa-var-hand-holding: \\f4bd;\n$fa-var-plug-circle-exclamation: \\e55d;\n$fa-var-link-slash: \\f127;\n$fa-var-chain-broken: \\f127;\n$fa-var-chain-slash: \\f127;\n$fa-var-unlink: \\f127;\n$fa-var-clone: \\f24d;\n$fa-var-person-walking-arrow-loop-left: \\e551;\n$fa-var-arrow-up-z-a: \\f882;\n$fa-var-sort-alpha-up-alt: \\f882;\n$fa-var-fire-flame-curved: \\f7e4;\n$fa-var-fire-alt: \\f7e4;\n$fa-var-tornado: \\f76f;\n$fa-var-file-circle-plus: \\e494;\n$fa-var-book-quran: \\f687;\n$fa-var-quran: \\f687;\n$fa-var-anchor: \\f13d;\n$fa-var-border-all: \\f84c;\n$fa-var-face-angry: \\f556;\n$fa-var-angry: \\f556;\n$fa-var-cookie-bite: \\f564;\n$fa-var-arrow-trend-down: \\e097;\n$fa-var-rss: \\f09e;\n$fa-var-feed: \\f09e;\n$fa-var-draw-polygon: \\f5ee;\n$fa-var-scale-balanced: \\f24e;\n$fa-var-balance-scale: \\f24e;\n$fa-var-gauge-simple-high: \\f62a;\n$fa-var-tachometer: \\f62a;\n$fa-var-tachometer-fast: \\f62a;\n$fa-var-shower: \\f2cc;\n$fa-var-desktop: \\f390;\n$fa-var-desktop-alt: \\f390;\n$fa-var-m: \\4d;\n$fa-var-table-list: \\f00b;\n$fa-var-th-list: \\f00b;\n$fa-var-comment-sms: \\f7cd;\n$fa-var-sms: \\f7cd;\n$fa-var-book: \\f02d;\n$fa-var-user-plus: \\f234;\n$fa-var-check: \\f00c;\n$fa-var-battery-three-quarters: \\f241;\n$fa-var-battery-4: \\f241;\n$fa-var-house-circle-check: \\e509;\n$fa-var-angle-left: \\f104;\n$fa-var-diagram-successor: \\e47a;\n$fa-var-truck-arrow-right: \\e58b;\n$fa-var-arrows-split-up-and-left: \\e4bc;\n$fa-var-hand-fist: \\f6de;\n$fa-var-fist-raised: \\f6de;\n$fa-var-cloud-moon: \\f6c3;\n$fa-var-briefcase: \\f0b1;\n$fa-var-person-falling: \\e546;\n$fa-var-image-portrait: \\f3e0;\n$fa-var-portrait: \\f3e0;\n$fa-var-user-tag: \\f507;\n$fa-var-rug: \\e569;\n$fa-var-earth-europe: \\f7a2;\n$fa-var-globe-europe: \\f7a2;\n$fa-var-cart-flatbed-suitcase: \\f59d;\n$fa-var-luggage-cart: \\f59d;\n$fa-var-rectangle-xmark: \\f410;\n$fa-var-rectangle-times: \\f410;\n$fa-var-times-rectangle: \\f410;\n$fa-var-window-close: \\f410;\n$fa-var-baht-sign: \\e0ac;\n$fa-var-book-open: \\f518;\n$fa-var-book-journal-whills: \\f66a;\n$fa-var-journal-whills: \\f66a;\n$fa-var-handcuffs: \\e4f8;\n$fa-var-triangle-exclamation: \\f071;\n$fa-var-exclamation-triangle: \\f071;\n$fa-var-warning: \\f071;\n$fa-var-database: \\f1c0;\n$fa-var-share: \\f064;\n$fa-var-mail-forward: \\f064;\n$fa-var-bottle-droplet: \\e4c4;\n$fa-var-mask-face: \\e1d7;\n$fa-var-hill-rockslide: \\e508;\n$fa-var-right-left: \\f362;\n$fa-var-exchange-alt: \\f362;\n$fa-var-paper-plane: \\f1d8;\n$fa-var-road-circle-exclamation: \\e565;\n$fa-var-dungeon: \\f6d9;\n$fa-var-align-right: \\f038;\n$fa-var-money-bill-1-wave: \\f53b;\n$fa-var-money-bill-wave-alt: \\f53b;\n$fa-var-life-ring: \\f1cd;\n$fa-var-hands: \\f2a7;\n$fa-var-sign-language: \\f2a7;\n$fa-var-signing: \\f2a7;\n$fa-var-calendar-day: \\f783;\n$fa-var-water-ladder: \\f5c5;\n$fa-var-ladder-water: \\f5c5;\n$fa-var-swimming-pool: \\f5c5;\n$fa-var-arrows-up-down: \\f07d;\n$fa-var-arrows-v: \\f07d;\n$fa-var-face-grimace: \\f57f;\n$fa-var-grimace: \\f57f;\n$fa-var-wheelchair-move: \\e2ce;\n$fa-var-wheelchair-alt: \\e2ce;\n$fa-var-turn-down: \\f3be;\n$fa-var-level-down-alt: \\f3be;\n$fa-var-person-walking-arrow-right: \\e552;\n$fa-var-square-envelope: \\f199;\n$fa-var-envelope-square: \\f199;\n$fa-var-dice: \\f522;\n$fa-var-bowling-ball: \\f436;\n$fa-var-brain: \\f5dc;\n$fa-var-bandage: \\f462;\n$fa-var-band-aid: \\f462;\n$fa-var-calendar-minus: \\f272;\n$fa-var-circle-xmark: \\f057;\n$fa-var-times-circle: \\f057;\n$fa-var-xmark-circle: \\f057;\n$fa-var-gifts: \\f79c;\n$fa-var-hotel: \\f594;\n$fa-var-earth-asia: \\f57e;\n$fa-var-globe-asia: \\f57e;\n$fa-var-id-card-clip: \\f47f;\n$fa-var-id-card-alt: \\f47f;\n$fa-var-magnifying-glass-plus: \\f00e;\n$fa-var-search-plus: \\f00e;\n$fa-var-thumbs-up: \\f164;\n$fa-var-user-clock: \\f4fd;\n$fa-var-hand-dots: \\f461;\n$fa-var-allergies: \\f461;\n$fa-var-file-invoice: \\f570;\n$fa-var-window-minimize: \\f2d1;\n$fa-var-mug-saucer: \\f0f4;\n$fa-var-coffee: \\f0f4;\n$fa-var-brush: \\f55d;\n$fa-var-file-half-dashed: \\e698;\n$fa-var-mask: \\f6fa;\n$fa-var-magnifying-glass-minus: \\f010;\n$fa-var-search-minus: \\f010;\n$fa-var-ruler-vertical: \\f548;\n$fa-var-user-large: \\f406;\n$fa-var-user-alt: \\f406;\n$fa-var-train-tram: \\e5b4;\n$fa-var-user-nurse: \\f82f;\n$fa-var-syringe: \\f48e;\n$fa-var-cloud-sun: \\f6c4;\n$fa-var-stopwatch-20: \\e06f;\n$fa-var-square-full: \\f45c;\n$fa-var-magnet: \\f076;\n$fa-var-jar: \\e516;\n$fa-var-note-sticky: \\f249;\n$fa-var-sticky-note: \\f249;\n$fa-var-bug-slash: \\e490;\n$fa-var-arrow-up-from-water-pump: \\e4b6;\n$fa-var-bone: \\f5d7;\n$fa-var-table-cells-row-unlock: \\e691;\n$fa-var-user-injured: \\f728;\n$fa-var-face-sad-tear: \\f5b4;\n$fa-var-sad-tear: \\f5b4;\n$fa-var-plane: \\f072;\n$fa-var-tent-arrows-down: \\e581;\n$fa-var-exclamation: \\21;\n$fa-var-arrows-spin: \\e4bb;\n$fa-var-print: \\f02f;\n$fa-var-turkish-lira-sign: \\e2bb;\n$fa-var-try: \\e2bb;\n$fa-var-turkish-lira: \\e2bb;\n$fa-var-dollar-sign: \\24;\n$fa-var-dollar: \\24;\n$fa-var-usd: \\24;\n$fa-var-x: \\58;\n$fa-var-magnifying-glass-dollar: \\f688;\n$fa-var-search-dollar: \\f688;\n$fa-var-users-gear: \\f509;\n$fa-var-users-cog: \\f509;\n$fa-var-person-military-pointing: \\e54a;\n$fa-var-building-columns: \\f19c;\n$fa-var-bank: \\f19c;\n$fa-var-institution: \\f19c;\n$fa-var-museum: \\f19c;\n$fa-var-university: \\f19c;\n$fa-var-umbrella: \\f0e9;\n$fa-var-trowel: \\e589;\n$fa-var-d: \\44;\n$fa-var-stapler: \\e5af;\n$fa-var-masks-theater: \\f630;\n$fa-var-theater-masks: \\f630;\n$fa-var-kip-sign: \\e1c4;\n$fa-var-hand-point-left: \\f0a5;\n$fa-var-handshake-simple: \\f4c6;\n$fa-var-handshake-alt: \\f4c6;\n$fa-var-jet-fighter: \\f0fb;\n$fa-var-fighter-jet: \\f0fb;\n$fa-var-square-share-nodes: \\f1e1;\n$fa-var-share-alt-square: \\f1e1;\n$fa-var-barcode: \\f02a;\n$fa-var-plus-minus: \\e43c;\n$fa-var-video: \\f03d;\n$fa-var-video-camera: \\f03d;\n$fa-var-graduation-cap: \\f19d;\n$fa-var-mortar-board: \\f19d;\n$fa-var-hand-holding-medical: \\e05c;\n$fa-var-person-circle-check: \\e53e;\n$fa-var-turn-up: \\f3bf;\n$fa-var-level-up-alt: \\f3bf;\n\n$fa-var-monero: \\f3d0;\n$fa-var-hooli: \\f427;\n$fa-var-yelp: \\f1e9;\n$fa-var-cc-visa: \\f1f0;\n$fa-var-lastfm: \\f202;\n$fa-var-shopware: \\f5b5;\n$fa-var-creative-commons-nc: \\f4e8;\n$fa-var-aws: \\f375;\n$fa-var-redhat: \\f7bc;\n$fa-var-yoast: \\f2b1;\n$fa-var-cloudflare: \\e07d;\n$fa-var-ups: \\f7e0;\n$fa-var-pixiv: \\e640;\n$fa-var-wpexplorer: \\f2de;\n$fa-var-dyalog: \\f399;\n$fa-var-bity: \\f37a;\n$fa-var-stackpath: \\f842;\n$fa-var-buysellads: \\f20d;\n$fa-var-first-order: \\f2b0;\n$fa-var-modx: \\f285;\n$fa-var-guilded: \\e07e;\n$fa-var-vnv: \\f40b;\n$fa-var-square-js: \\f3b9;\n$fa-var-js-square: \\f3b9;\n$fa-var-microsoft: \\f3ca;\n$fa-var-qq: \\f1d6;\n$fa-var-orcid: \\f8d2;\n$fa-var-java: \\f4e4;\n$fa-var-invision: \\f7b0;\n$fa-var-creative-commons-pd-alt: \\f4ed;\n$fa-var-centercode: \\f380;\n$fa-var-glide-g: \\f2a6;\n$fa-var-drupal: \\f1a9;\n$fa-var-jxl: \\e67b;\n$fa-var-dart-lang: \\e693;\n$fa-var-hire-a-helper: \\f3b0;\n$fa-var-creative-commons-by: \\f4e7;\n$fa-var-unity: \\e049;\n$fa-var-whmcs: \\f40d;\n$fa-var-rocketchat: \\f3e8;\n$fa-var-vk: \\f189;\n$fa-var-untappd: \\f405;\n$fa-var-mailchimp: \\f59e;\n$fa-var-css3-alt: \\f38b;\n$fa-var-square-reddit: \\f1a2;\n$fa-var-reddit-square: \\f1a2;\n$fa-var-vimeo-v: \\f27d;\n$fa-var-contao: \\f26d;\n$fa-var-square-font-awesome: \\e5ad;\n$fa-var-deskpro: \\f38f;\n$fa-var-brave: \\e63c;\n$fa-var-sistrix: \\f3ee;\n$fa-var-square-instagram: \\e055;\n$fa-var-instagram-square: \\e055;\n$fa-var-battle-net: \\f835;\n$fa-var-the-red-yeti: \\f69d;\n$fa-var-square-hacker-news: \\f3af;\n$fa-var-hacker-news-square: \\f3af;\n$fa-var-edge: \\f282;\n$fa-var-threads: \\e618;\n$fa-var-napster: \\f3d2;\n$fa-var-square-snapchat: \\f2ad;\n$fa-var-snapchat-square: \\f2ad;\n$fa-var-google-plus-g: \\f0d5;\n$fa-var-artstation: \\f77a;\n$fa-var-markdown: \\f60f;\n$fa-var-sourcetree: \\f7d3;\n$fa-var-google-plus: \\f2b3;\n$fa-var-diaspora: \\f791;\n$fa-var-foursquare: \\f180;\n$fa-var-stack-overflow: \\f16c;\n$fa-var-github-alt: \\f113;\n$fa-var-phoenix-squadron: \\f511;\n$fa-var-pagelines: \\f18c;\n$fa-var-algolia: \\f36c;\n$fa-var-red-river: \\f3e3;\n$fa-var-creative-commons-sa: \\f4ef;\n$fa-var-safari: \\f267;\n$fa-var-google: \\f1a0;\n$fa-var-square-font-awesome-stroke: \\f35c;\n$fa-var-font-awesome-alt: \\f35c;\n$fa-var-atlassian: \\f77b;\n$fa-var-linkedin-in: \\f0e1;\n$fa-var-digital-ocean: \\f391;\n$fa-var-nimblr: \\f5a8;\n$fa-var-chromecast: \\f838;\n$fa-var-evernote: \\f839;\n$fa-var-hacker-news: \\f1d4;\n$fa-var-creative-commons-sampling: \\f4f0;\n$fa-var-adversal: \\f36a;\n$fa-var-creative-commons: \\f25e;\n$fa-var-watchman-monitoring: \\e087;\n$fa-var-fonticons: \\f280;\n$fa-var-weixin: \\f1d7;\n$fa-var-shirtsinbulk: \\f214;\n$fa-var-codepen: \\f1cb;\n$fa-var-git-alt: \\f841;\n$fa-var-lyft: \\f3c3;\n$fa-var-rev: \\f5b2;\n$fa-var-windows: \\f17a;\n$fa-var-wizards-of-the-coast: \\f730;\n$fa-var-square-viadeo: \\f2aa;\n$fa-var-viadeo-square: \\f2aa;\n$fa-var-meetup: \\f2e0;\n$fa-var-centos: \\f789;\n$fa-var-adn: \\f170;\n$fa-var-cloudsmith: \\f384;\n$fa-var-opensuse: \\e62b;\n$fa-var-pied-piper-alt: \\f1a8;\n$fa-var-square-dribbble: \\f397;\n$fa-var-dribbble-square: \\f397;\n$fa-var-codiepie: \\f284;\n$fa-var-node: \\f419;\n$fa-var-mix: \\f3cb;\n$fa-var-steam: \\f1b6;\n$fa-var-cc-apple-pay: \\f416;\n$fa-var-scribd: \\f28a;\n$fa-var-debian: \\e60b;\n$fa-var-openid: \\f19b;\n$fa-var-instalod: \\e081;\n$fa-var-files-pinwheel: \\e69f;\n$fa-var-expeditedssl: \\f23e;\n$fa-var-sellcast: \\f2da;\n$fa-var-square-twitter: \\f081;\n$fa-var-twitter-square: \\f081;\n$fa-var-r-project: \\f4f7;\n$fa-var-delicious: \\f1a5;\n$fa-var-freebsd: \\f3a4;\n$fa-var-vuejs: \\f41f;\n$fa-var-accusoft: \\f369;\n$fa-var-ioxhost: \\f208;\n$fa-var-fonticons-fi: \\f3a2;\n$fa-var-app-store: \\f36f;\n$fa-var-cc-mastercard: \\f1f1;\n$fa-var-itunes-note: \\f3b5;\n$fa-var-golang: \\e40f;\n$fa-var-kickstarter: \\f3bb;\n$fa-var-square-kickstarter: \\f3bb;\n$fa-var-grav: \\f2d6;\n$fa-var-weibo: \\f18a;\n$fa-var-uncharted: \\e084;\n$fa-var-firstdraft: \\f3a1;\n$fa-var-square-youtube: \\f431;\n$fa-var-youtube-square: \\f431;\n$fa-var-wikipedia-w: \\f266;\n$fa-var-wpressr: \\f3e4;\n$fa-var-rendact: \\f3e4;\n$fa-var-angellist: \\f209;\n$fa-var-galactic-republic: \\f50c;\n$fa-var-nfc-directional: \\e530;\n$fa-var-skype: \\f17e;\n$fa-var-joget: \\f3b7;\n$fa-var-fedora: \\f798;\n$fa-var-stripe-s: \\f42a;\n$fa-var-meta: \\e49b;\n$fa-var-laravel: \\f3bd;\n$fa-var-hotjar: \\f3b1;\n$fa-var-bluetooth-b: \\f294;\n$fa-var-square-letterboxd: \\e62e;\n$fa-var-sticker-mule: \\f3f7;\n$fa-var-creative-commons-zero: \\f4f3;\n$fa-var-hips: \\f452;\n$fa-var-css: \\e6a2;\n$fa-var-behance: \\f1b4;\n$fa-var-reddit: \\f1a1;\n$fa-var-discord: \\f392;\n$fa-var-chrome: \\f268;\n$fa-var-app-store-ios: \\f370;\n$fa-var-cc-discover: \\f1f2;\n$fa-var-wpbeginner: \\f297;\n$fa-var-confluence: \\f78d;\n$fa-var-shoelace: \\e60c;\n$fa-var-mdb: \\f8ca;\n$fa-var-dochub: \\f394;\n$fa-var-accessible-icon: \\f368;\n$fa-var-ebay: \\f4f4;\n$fa-var-amazon: \\f270;\n$fa-var-unsplash: \\e07c;\n$fa-var-yarn: \\f7e3;\n$fa-var-square-steam: \\f1b7;\n$fa-var-steam-square: \\f1b7;\n$fa-var-500px: \\f26e;\n$fa-var-square-vimeo: \\f194;\n$fa-var-vimeo-square: \\f194;\n$fa-var-asymmetrik: \\f372;\n$fa-var-font-awesome: \\f2b4;\n$fa-var-font-awesome-flag: \\f2b4;\n$fa-var-font-awesome-logo-full: \\f2b4;\n$fa-var-gratipay: \\f184;\n$fa-var-apple: \\f179;\n$fa-var-hive: \\e07f;\n$fa-var-gitkraken: \\f3a6;\n$fa-var-keybase: \\f4f5;\n$fa-var-apple-pay: \\f415;\n$fa-var-padlet: \\e4a0;\n$fa-var-amazon-pay: \\f42c;\n$fa-var-square-github: \\f092;\n$fa-var-github-square: \\f092;\n$fa-var-stumbleupon: \\f1a4;\n$fa-var-fedex: \\f797;\n$fa-var-phoenix-framework: \\f3dc;\n$fa-var-shopify: \\e057;\n$fa-var-neos: \\f612;\n$fa-var-square-threads: \\e619;\n$fa-var-hackerrank: \\f5f7;\n$fa-var-researchgate: \\f4f8;\n$fa-var-swift: \\f8e1;\n$fa-var-angular: \\f420;\n$fa-var-speakap: \\f3f3;\n$fa-var-angrycreative: \\f36e;\n$fa-var-y-combinator: \\f23b;\n$fa-var-empire: \\f1d1;\n$fa-var-envira: \\f299;\n$fa-var-google-scholar: \\e63b;\n$fa-var-square-gitlab: \\e5ae;\n$fa-var-gitlab-square: \\e5ae;\n$fa-var-studiovinari: \\f3f8;\n$fa-var-pied-piper: \\f2ae;\n$fa-var-wordpress: \\f19a;\n$fa-var-product-hunt: \\f288;\n$fa-var-firefox: \\f269;\n$fa-var-linode: \\f2b8;\n$fa-var-goodreads: \\f3a8;\n$fa-var-square-odnoklassniki: \\f264;\n$fa-var-odnoklassniki-square: \\f264;\n$fa-var-jsfiddle: \\f1cc;\n$fa-var-sith: \\f512;\n$fa-var-themeisle: \\f2b2;\n$fa-var-page4: \\f3d7;\n$fa-var-hashnode: \\e499;\n$fa-var-react: \\f41b;\n$fa-var-cc-paypal: \\f1f4;\n$fa-var-squarespace: \\f5be;\n$fa-var-cc-stripe: \\f1f5;\n$fa-var-creative-commons-share: \\f4f2;\n$fa-var-bitcoin: \\f379;\n$fa-var-keycdn: \\f3ba;\n$fa-var-opera: \\f26a;\n$fa-var-itch-io: \\f83a;\n$fa-var-umbraco: \\f8e8;\n$fa-var-galactic-senate: \\f50d;\n$fa-var-ubuntu: \\f7df;\n$fa-var-draft2digital: \\f396;\n$fa-var-stripe: \\f429;\n$fa-var-houzz: \\f27c;\n$fa-var-gg: \\f260;\n$fa-var-dhl: \\f790;\n$fa-var-square-pinterest: \\f0d3;\n$fa-var-pinterest-square: \\f0d3;\n$fa-var-xing: \\f168;\n$fa-var-blackberry: \\f37b;\n$fa-var-creative-commons-pd: \\f4ec;\n$fa-var-playstation: \\f3df;\n$fa-var-quinscape: \\f459;\n$fa-var-less: \\f41d;\n$fa-var-blogger-b: \\f37d;\n$fa-var-opencart: \\f23d;\n$fa-var-vine: \\f1ca;\n$fa-var-signal-messenger: \\e663;\n$fa-var-paypal: \\f1ed;\n$fa-var-gitlab: \\f296;\n$fa-var-typo3: \\f42b;\n$fa-var-reddit-alien: \\f281;\n$fa-var-yahoo: \\f19e;\n$fa-var-dailymotion: \\e052;\n$fa-var-affiliatetheme: \\f36b;\n$fa-var-pied-piper-pp: \\f1a7;\n$fa-var-bootstrap: \\f836;\n$fa-var-odnoklassniki: \\f263;\n$fa-var-nfc-symbol: \\e531;\n$fa-var-mintbit: \\e62f;\n$fa-var-ethereum: \\f42e;\n$fa-var-speaker-deck: \\f83c;\n$fa-var-creative-commons-nc-eu: \\f4e9;\n$fa-var-patreon: \\f3d9;\n$fa-var-avianex: \\f374;\n$fa-var-ello: \\f5f1;\n$fa-var-gofore: \\f3a7;\n$fa-var-bimobject: \\f378;\n$fa-var-brave-reverse: \\e63d;\n$fa-var-facebook-f: \\f39e;\n$fa-var-square-google-plus: \\f0d4;\n$fa-var-google-plus-square: \\f0d4;\n$fa-var-web-awesome: \\e682;\n$fa-var-mandalorian: \\f50f;\n$fa-var-first-order-alt: \\f50a;\n$fa-var-osi: \\f41a;\n$fa-var-google-wallet: \\f1ee;\n$fa-var-d-and-d-beyond: \\f6ca;\n$fa-var-periscope: \\f3da;\n$fa-var-fulcrum: \\f50b;\n$fa-var-cloudscale: \\f383;\n$fa-var-forumbee: \\f211;\n$fa-var-mizuni: \\f3cc;\n$fa-var-schlix: \\f3ea;\n$fa-var-square-xing: \\f169;\n$fa-var-xing-square: \\f169;\n$fa-var-bandcamp: \\f2d5;\n$fa-var-wpforms: \\f298;\n$fa-var-cloudversify: \\f385;\n$fa-var-usps: \\f7e1;\n$fa-var-megaport: \\f5a3;\n$fa-var-magento: \\f3c4;\n$fa-var-spotify: \\f1bc;\n$fa-var-optin-monster: \\f23c;\n$fa-var-fly: \\f417;\n$fa-var-square-bluesky: \\e6a3;\n$fa-var-aviato: \\f421;\n$fa-var-itunes: \\f3b4;\n$fa-var-cuttlefish: \\f38c;\n$fa-var-blogger: \\f37c;\n$fa-var-flickr: \\f16e;\n$fa-var-viber: \\f409;\n$fa-var-soundcloud: \\f1be;\n$fa-var-digg: \\f1a6;\n$fa-var-tencent-weibo: \\f1d5;\n$fa-var-letterboxd: \\e62d;\n$fa-var-symfony: \\f83d;\n$fa-var-maxcdn: \\f136;\n$fa-var-etsy: \\f2d7;\n$fa-var-facebook-messenger: \\f39f;\n$fa-var-audible: \\f373;\n$fa-var-think-peaks: \\f731;\n$fa-var-bilibili: \\e3d9;\n$fa-var-erlang: \\f39d;\n$fa-var-x-twitter: \\e61b;\n$fa-var-cotton-bureau: \\f89e;\n$fa-var-dashcube: \\f210;\n$fa-var-42-group: \\e080;\n$fa-var-innosoft: \\e080;\n$fa-var-stack-exchange: \\f18d;\n$fa-var-elementor: \\f430;\n$fa-var-square-pied-piper: \\e01e;\n$fa-var-pied-piper-square: \\e01e;\n$fa-var-creative-commons-nd: \\f4eb;\n$fa-var-palfed: \\f3d8;\n$fa-var-superpowers: \\f2dd;\n$fa-var-resolving: \\f3e7;\n$fa-var-xbox: \\f412;\n$fa-var-square-web-awesome-stroke: \\e684;\n$fa-var-searchengin: \\f3eb;\n$fa-var-tiktok: \\e07b;\n$fa-var-square-facebook: \\f082;\n$fa-var-facebook-square: \\f082;\n$fa-var-renren: \\f18b;\n$fa-var-linux: \\f17c;\n$fa-var-glide: \\f2a5;\n$fa-var-linkedin: \\f08c;\n$fa-var-hubspot: \\f3b2;\n$fa-var-deploydog: \\f38e;\n$fa-var-twitch: \\f1e8;\n$fa-var-flutter: \\e694;\n$fa-var-ravelry: \\f2d9;\n$fa-var-mixer: \\e056;\n$fa-var-square-lastfm: \\f203;\n$fa-var-lastfm-square: \\f203;\n$fa-var-vimeo: \\f40a;\n$fa-var-mendeley: \\f7b3;\n$fa-var-uniregistry: \\f404;\n$fa-var-figma: \\f799;\n$fa-var-creative-commons-remix: \\f4ee;\n$fa-var-cc-amazon-pay: \\f42d;\n$fa-var-dropbox: \\f16b;\n$fa-var-instagram: \\f16d;\n$fa-var-cmplid: \\e360;\n$fa-var-upwork: \\e641;\n$fa-var-facebook: \\f09a;\n$fa-var-gripfire: \\f3ac;\n$fa-var-jedi-order: \\f50e;\n$fa-var-uikit: \\f403;\n$fa-var-fort-awesome-alt: \\f3a3;\n$fa-var-phabricator: \\f3db;\n$fa-var-ussunnah: \\f407;\n$fa-var-earlybirds: \\f39a;\n$fa-var-trade-federation: \\f513;\n$fa-var-autoprefixer: \\f41c;\n$fa-var-whatsapp: \\f232;\n$fa-var-square-upwork: \\e67c;\n$fa-var-slideshare: \\f1e7;\n$fa-var-google-play: \\f3ab;\n$fa-var-viadeo: \\f2a9;\n$fa-var-line: \\f3c0;\n$fa-var-google-drive: \\f3aa;\n$fa-var-servicestack: \\f3ec;\n$fa-var-simplybuilt: \\f215;\n$fa-var-bitbucket: \\f171;\n$fa-var-imdb: \\f2d8;\n$fa-var-deezer: \\e077;\n$fa-var-raspberry-pi: \\f7bb;\n$fa-var-jira: \\f7b1;\n$fa-var-docker: \\f395;\n$fa-var-screenpal: \\e570;\n$fa-var-bluetooth: \\f293;\n$fa-var-gitter: \\f426;\n$fa-var-d-and-d: \\f38d;\n$fa-var-microblog: \\e01a;\n$fa-var-cc-diners-club: \\f24c;\n$fa-var-gg-circle: \\f261;\n$fa-var-pied-piper-hat: \\f4e5;\n$fa-var-kickstarter-k: \\f3bc;\n$fa-var-yandex: \\f413;\n$fa-var-readme: \\f4d5;\n$fa-var-html5: \\f13b;\n$fa-var-sellsy: \\f213;\n$fa-var-square-web-awesome: \\e683;\n$fa-var-sass: \\f41e;\n$fa-var-wirsindhandwerk: \\e2d0;\n$fa-var-wsh: \\e2d0;\n$fa-var-buromobelexperte: \\f37f;\n$fa-var-salesforce: \\f83b;\n$fa-var-octopus-deploy: \\e082;\n$fa-var-medapps: \\f3c6;\n$fa-var-ns8: \\f3d5;\n$fa-var-pinterest-p: \\f231;\n$fa-var-apper: \\f371;\n$fa-var-fort-awesome: \\f286;\n$fa-var-waze: \\f83f;\n$fa-var-bluesky: \\e671;\n$fa-var-cc-jcb: \\f24b;\n$fa-var-snapchat: \\f2ab;\n$fa-var-snapchat-ghost: \\f2ab;\n$fa-var-fantasy-flight-games: \\f6dc;\n$fa-var-rust: \\e07a;\n$fa-var-wix: \\f5cf;\n$fa-var-square-behance: \\f1b5;\n$fa-var-behance-square: \\f1b5;\n$fa-var-supple: \\f3f9;\n$fa-var-webflow: \\e65c;\n$fa-var-rebel: \\f1d0;\n$fa-var-css3: \\f13c;\n$fa-var-staylinked: \\f3f5;\n$fa-var-kaggle: \\f5fa;\n$fa-var-space-awesome: \\e5ac;\n$fa-var-deviantart: \\f1bd;\n$fa-var-cpanel: \\f388;\n$fa-var-goodreads-g: \\f3a9;\n$fa-var-square-git: \\f1d2;\n$fa-var-git-square: \\f1d2;\n$fa-var-square-tumblr: \\f174;\n$fa-var-tumblr-square: \\f174;\n$fa-var-trello: \\f181;\n$fa-var-creative-commons-nc-jp: \\f4ea;\n$fa-var-get-pocket: \\f265;\n$fa-var-perbyte: \\e083;\n$fa-var-grunt: \\f3ad;\n$fa-var-weebly: \\f5cc;\n$fa-var-connectdevelop: \\f20e;\n$fa-var-leanpub: \\f212;\n$fa-var-black-tie: \\f27e;\n$fa-var-themeco: \\f5c6;\n$fa-var-python: \\f3e2;\n$fa-var-android: \\f17b;\n$fa-var-bots: \\e340;\n$fa-var-free-code-camp: \\f2c5;\n$fa-var-hornbill: \\f592;\n$fa-var-js: \\f3b8;\n$fa-var-ideal: \\e013;\n$fa-var-git: \\f1d3;\n$fa-var-dev: \\f6cc;\n$fa-var-sketch: \\f7c6;\n$fa-var-yandex-international: \\f414;\n$fa-var-cc-amex: \\f1f3;\n$fa-var-uber: \\f402;\n$fa-var-github: \\f09b;\n$fa-var-php: \\f457;\n$fa-var-alipay: \\f642;\n$fa-var-youtube: \\f167;\n$fa-var-skyatlas: \\f216;\n$fa-var-firefox-browser: \\e007;\n$fa-var-replyd: \\f3e6;\n$fa-var-suse: \\f7d6;\n$fa-var-jenkins: \\f3b6;\n$fa-var-twitter: \\f099;\n$fa-var-rockrms: \\f3e9;\n$fa-var-pinterest: \\f0d2;\n$fa-var-buffer: \\f837;\n$fa-var-npm: \\f3d4;\n$fa-var-yammer: \\f840;\n$fa-var-btc: \\f15a;\n$fa-var-dribbble: \\f17d;\n$fa-var-stumbleupon-circle: \\f1a3;\n$fa-var-internet-explorer: \\f26b;\n$fa-var-stubber: \\e5c7;\n$fa-var-telegram: \\f2c6;\n$fa-var-telegram-plane: \\f2c6;\n$fa-var-old-republic: \\f510;\n$fa-var-odysee: \\e5c6;\n$fa-var-square-whatsapp: \\f40c;\n$fa-var-whatsapp-square: \\f40c;\n$fa-var-node-js: \\f3d3;\n$fa-var-edge-legacy: \\e078;\n$fa-var-slack: \\f198;\n$fa-var-slack-hash: \\f198;\n$fa-var-medrt: \\f3c8;\n$fa-var-usb: \\f287;\n$fa-var-tumblr: \\f173;\n$fa-var-vaadin: \\f408;\n$fa-var-quora: \\f2c4;\n$fa-var-square-x-twitter: \\e61a;\n$fa-var-reacteurope: \\f75d;\n$fa-var-medium: \\f23a;\n$fa-var-medium-m: \\f23a;\n$fa-var-amilia: \\f36d;\n$fa-var-mixcloud: \\f289;\n$fa-var-flipboard: \\f44d;\n$fa-var-viacoin: \\f237;\n$fa-var-critical-role: \\f6c9;\n$fa-var-sitrox: \\e44a;\n$fa-var-discourse: \\f393;\n$fa-var-joomla: \\f1aa;\n$fa-var-mastodon: \\f4f6;\n$fa-var-airbnb: \\f834;\n$fa-var-wolf-pack-battalion: \\f514;\n$fa-var-buy-n-large: \\f8a6;\n$fa-var-gulp: \\f3ae;\n$fa-var-creative-commons-sampling-plus: \\f4f1;\n$fa-var-strava: \\f428;\n$fa-var-ember: \\f423;\n$fa-var-canadian-maple-leaf: \\f785;\n$fa-var-teamspeak: \\f4f9;\n$fa-var-pushed: \\f3e1;\n$fa-var-wordpress-simple: \\f411;\n$fa-var-nutritionix: \\f3d6;\n$fa-var-wodu: \\e088;\n$fa-var-google-pay: \\e079;\n$fa-var-intercom: \\f7af;\n$fa-var-zhihu: \\f63f;\n$fa-var-korvue: \\f42f;\n$fa-var-pix: \\e43a;\n$fa-var-steam-symbol: \\f3f6;\n\n$fa-icons: (\n \"0\": $fa-var-0,\n \"1\": $fa-var-1,\n \"2\": $fa-var-2,\n \"3\": $fa-var-3,\n \"4\": $fa-var-4,\n \"5\": $fa-var-5,\n \"6\": $fa-var-6,\n \"7\": $fa-var-7,\n \"8\": $fa-var-8,\n \"9\": $fa-var-9,\n \"fill-drip\": $fa-var-fill-drip,\n \"arrows-to-circle\": $fa-var-arrows-to-circle,\n \"circle-chevron-right\": $fa-var-circle-chevron-right,\n \"chevron-circle-right\": $fa-var-chevron-circle-right,\n \"at\": $fa-var-at,\n \"trash-can\": $fa-var-trash-can,\n \"trash-alt\": $fa-var-trash-alt,\n \"text-height\": $fa-var-text-height,\n \"user-xmark\": $fa-var-user-xmark,\n \"user-times\": $fa-var-user-times,\n \"stethoscope\": $fa-var-stethoscope,\n \"message\": $fa-var-message,\n \"comment-alt\": $fa-var-comment-alt,\n \"info\": $fa-var-info,\n \"down-left-and-up-right-to-center\": $fa-var-down-left-and-up-right-to-center,\n \"compress-alt\": $fa-var-compress-alt,\n \"explosion\": $fa-var-explosion,\n \"file-lines\": $fa-var-file-lines,\n \"file-alt\": $fa-var-file-alt,\n \"file-text\": $fa-var-file-text,\n \"wave-square\": $fa-var-wave-square,\n \"ring\": $fa-var-ring,\n \"building-un\": $fa-var-building-un,\n \"dice-three\": $fa-var-dice-three,\n \"calendar-days\": $fa-var-calendar-days,\n \"calendar-alt\": $fa-var-calendar-alt,\n \"anchor-circle-check\": $fa-var-anchor-circle-check,\n \"building-circle-arrow-right\": $fa-var-building-circle-arrow-right,\n \"volleyball\": $fa-var-volleyball,\n \"volleyball-ball\": $fa-var-volleyball-ball,\n \"arrows-up-to-line\": $fa-var-arrows-up-to-line,\n \"sort-down\": $fa-var-sort-down,\n \"sort-desc\": $fa-var-sort-desc,\n \"circle-minus\": $fa-var-circle-minus,\n \"minus-circle\": $fa-var-minus-circle,\n \"door-open\": $fa-var-door-open,\n \"right-from-bracket\": $fa-var-right-from-bracket,\n \"sign-out-alt\": $fa-var-sign-out-alt,\n \"atom\": $fa-var-atom,\n \"soap\": $fa-var-soap,\n \"icons\": $fa-var-icons,\n \"heart-music-camera-bolt\": $fa-var-heart-music-camera-bolt,\n \"microphone-lines-slash\": $fa-var-microphone-lines-slash,\n \"microphone-alt-slash\": $fa-var-microphone-alt-slash,\n \"bridge-circle-check\": $fa-var-bridge-circle-check,\n \"pump-medical\": $fa-var-pump-medical,\n \"fingerprint\": $fa-var-fingerprint,\n \"hand-point-right\": $fa-var-hand-point-right,\n \"magnifying-glass-location\": $fa-var-magnifying-glass-location,\n \"search-location\": $fa-var-search-location,\n \"forward-step\": $fa-var-forward-step,\n \"step-forward\": $fa-var-step-forward,\n \"face-smile-beam\": $fa-var-face-smile-beam,\n \"smile-beam\": $fa-var-smile-beam,\n \"flag-checkered\": $fa-var-flag-checkered,\n \"football\": $fa-var-football,\n \"football-ball\": $fa-var-football-ball,\n \"school-circle-exclamation\": $fa-var-school-circle-exclamation,\n \"crop\": $fa-var-crop,\n \"angles-down\": $fa-var-angles-down,\n \"angle-double-down\": $fa-var-angle-double-down,\n \"users-rectangle\": $fa-var-users-rectangle,\n \"people-roof\": $fa-var-people-roof,\n \"people-line\": $fa-var-people-line,\n \"beer-mug-empty\": $fa-var-beer-mug-empty,\n \"beer\": $fa-var-beer,\n \"diagram-predecessor\": $fa-var-diagram-predecessor,\n \"arrow-up-long\": $fa-var-arrow-up-long,\n \"long-arrow-up\": $fa-var-long-arrow-up,\n \"fire-flame-simple\": $fa-var-fire-flame-simple,\n \"burn\": $fa-var-burn,\n \"person\": $fa-var-person,\n \"male\": $fa-var-male,\n \"laptop\": $fa-var-laptop,\n \"file-csv\": $fa-var-file-csv,\n \"menorah\": $fa-var-menorah,\n \"truck-plane\": $fa-var-truck-plane,\n \"record-vinyl\": $fa-var-record-vinyl,\n \"face-grin-stars\": $fa-var-face-grin-stars,\n \"grin-stars\": $fa-var-grin-stars,\n \"bong\": $fa-var-bong,\n \"spaghetti-monster-flying\": $fa-var-spaghetti-monster-flying,\n \"pastafarianism\": $fa-var-pastafarianism,\n \"arrow-down-up-across-line\": $fa-var-arrow-down-up-across-line,\n \"spoon\": $fa-var-spoon,\n \"utensil-spoon\": $fa-var-utensil-spoon,\n \"jar-wheat\": $fa-var-jar-wheat,\n \"envelopes-bulk\": $fa-var-envelopes-bulk,\n \"mail-bulk\": $fa-var-mail-bulk,\n \"file-circle-exclamation\": $fa-var-file-circle-exclamation,\n \"circle-h\": $fa-var-circle-h,\n \"hospital-symbol\": $fa-var-hospital-symbol,\n \"pager\": $fa-var-pager,\n \"address-book\": $fa-var-address-book,\n \"contact-book\": $fa-var-contact-book,\n \"strikethrough\": $fa-var-strikethrough,\n \"k\": $fa-var-k,\n \"landmark-flag\": $fa-var-landmark-flag,\n \"pencil\": $fa-var-pencil,\n \"pencil-alt\": $fa-var-pencil-alt,\n \"backward\": $fa-var-backward,\n \"caret-right\": $fa-var-caret-right,\n \"comments\": $fa-var-comments,\n \"paste\": $fa-var-paste,\n \"file-clipboard\": $fa-var-file-clipboard,\n \"code-pull-request\": $fa-var-code-pull-request,\n \"clipboard-list\": $fa-var-clipboard-list,\n \"truck-ramp-box\": $fa-var-truck-ramp-box,\n \"truck-loading\": $fa-var-truck-loading,\n \"user-check\": $fa-var-user-check,\n \"vial-virus\": $fa-var-vial-virus,\n \"sheet-plastic\": $fa-var-sheet-plastic,\n \"blog\": $fa-var-blog,\n \"user-ninja\": $fa-var-user-ninja,\n \"person-arrow-up-from-line\": $fa-var-person-arrow-up-from-line,\n \"scroll-torah\": $fa-var-scroll-torah,\n \"torah\": $fa-var-torah,\n \"broom-ball\": $fa-var-broom-ball,\n \"quidditch\": $fa-var-quidditch,\n \"quidditch-broom-ball\": $fa-var-quidditch-broom-ball,\n \"toggle-off\": $fa-var-toggle-off,\n \"box-archive\": $fa-var-box-archive,\n \"archive\": $fa-var-archive,\n \"person-drowning\": $fa-var-person-drowning,\n \"arrow-down-9-1\": $fa-var-arrow-down-9-1,\n \"sort-numeric-desc\": $fa-var-sort-numeric-desc,\n \"sort-numeric-down-alt\": $fa-var-sort-numeric-down-alt,\n \"face-grin-tongue-squint\": $fa-var-face-grin-tongue-squint,\n \"grin-tongue-squint\": $fa-var-grin-tongue-squint,\n \"spray-can\": $fa-var-spray-can,\n \"truck-monster\": $fa-var-truck-monster,\n \"w\": $fa-var-w,\n \"earth-africa\": $fa-var-earth-africa,\n \"globe-africa\": $fa-var-globe-africa,\n \"rainbow\": $fa-var-rainbow,\n \"circle-notch\": $fa-var-circle-notch,\n \"tablet-screen-button\": $fa-var-tablet-screen-button,\n \"tablet-alt\": $fa-var-tablet-alt,\n \"paw\": $fa-var-paw,\n \"cloud\": $fa-var-cloud,\n \"trowel-bricks\": $fa-var-trowel-bricks,\n \"face-flushed\": $fa-var-face-flushed,\n \"flushed\": $fa-var-flushed,\n \"hospital-user\": $fa-var-hospital-user,\n \"tent-arrow-left-right\": $fa-var-tent-arrow-left-right,\n \"gavel\": $fa-var-gavel,\n \"legal\": $fa-var-legal,\n \"binoculars\": $fa-var-binoculars,\n \"microphone-slash\": $fa-var-microphone-slash,\n \"box-tissue\": $fa-var-box-tissue,\n \"motorcycle\": $fa-var-motorcycle,\n \"bell-concierge\": $fa-var-bell-concierge,\n \"concierge-bell\": $fa-var-concierge-bell,\n \"pen-ruler\": $fa-var-pen-ruler,\n \"pencil-ruler\": $fa-var-pencil-ruler,\n \"people-arrows\": $fa-var-people-arrows,\n \"people-arrows-left-right\": $fa-var-people-arrows-left-right,\n \"mars-and-venus-burst\": $fa-var-mars-and-venus-burst,\n \"square-caret-right\": $fa-var-square-caret-right,\n \"caret-square-right\": $fa-var-caret-square-right,\n \"scissors\": $fa-var-scissors,\n \"cut\": $fa-var-cut,\n \"sun-plant-wilt\": $fa-var-sun-plant-wilt,\n \"toilets-portable\": $fa-var-toilets-portable,\n \"hockey-puck\": $fa-var-hockey-puck,\n \"table\": $fa-var-table,\n \"magnifying-glass-arrow-right\": $fa-var-magnifying-glass-arrow-right,\n \"tachograph-digital\": $fa-var-tachograph-digital,\n \"digital-tachograph\": $fa-var-digital-tachograph,\n \"users-slash\": $fa-var-users-slash,\n \"clover\": $fa-var-clover,\n \"reply\": $fa-var-reply,\n \"mail-reply\": $fa-var-mail-reply,\n \"star-and-crescent\": $fa-var-star-and-crescent,\n \"house-fire\": $fa-var-house-fire,\n \"square-minus\": $fa-var-square-minus,\n \"minus-square\": $fa-var-minus-square,\n \"helicopter\": $fa-var-helicopter,\n \"compass\": $fa-var-compass,\n \"square-caret-down\": $fa-var-square-caret-down,\n \"caret-square-down\": $fa-var-caret-square-down,\n \"file-circle-question\": $fa-var-file-circle-question,\n \"laptop-code\": $fa-var-laptop-code,\n \"swatchbook\": $fa-var-swatchbook,\n \"prescription-bottle\": $fa-var-prescription-bottle,\n \"bars\": $fa-var-bars,\n \"navicon\": $fa-var-navicon,\n \"people-group\": $fa-var-people-group,\n \"hourglass-end\": $fa-var-hourglass-end,\n \"hourglass-3\": $fa-var-hourglass-3,\n \"heart-crack\": $fa-var-heart-crack,\n \"heart-broken\": $fa-var-heart-broken,\n \"square-up-right\": $fa-var-square-up-right,\n \"external-link-square-alt\": $fa-var-external-link-square-alt,\n \"face-kiss-beam\": $fa-var-face-kiss-beam,\n \"kiss-beam\": $fa-var-kiss-beam,\n \"film\": $fa-var-film,\n \"ruler-horizontal\": $fa-var-ruler-horizontal,\n \"people-robbery\": $fa-var-people-robbery,\n \"lightbulb\": $fa-var-lightbulb,\n \"caret-left\": $fa-var-caret-left,\n \"circle-exclamation\": $fa-var-circle-exclamation,\n \"exclamation-circle\": $fa-var-exclamation-circle,\n \"school-circle-xmark\": $fa-var-school-circle-xmark,\n \"arrow-right-from-bracket\": $fa-var-arrow-right-from-bracket,\n \"sign-out\": $fa-var-sign-out,\n \"circle-chevron-down\": $fa-var-circle-chevron-down,\n \"chevron-circle-down\": $fa-var-chevron-circle-down,\n \"unlock-keyhole\": $fa-var-unlock-keyhole,\n \"unlock-alt\": $fa-var-unlock-alt,\n \"cloud-showers-heavy\": $fa-var-cloud-showers-heavy,\n \"headphones-simple\": $fa-var-headphones-simple,\n \"headphones-alt\": $fa-var-headphones-alt,\n \"sitemap\": $fa-var-sitemap,\n \"circle-dollar-to-slot\": $fa-var-circle-dollar-to-slot,\n \"donate\": $fa-var-donate,\n \"memory\": $fa-var-memory,\n \"road-spikes\": $fa-var-road-spikes,\n \"fire-burner\": $fa-var-fire-burner,\n \"flag\": $fa-var-flag,\n \"hanukiah\": $fa-var-hanukiah,\n \"feather\": $fa-var-feather,\n \"volume-low\": $fa-var-volume-low,\n \"volume-down\": $fa-var-volume-down,\n \"comment-slash\": $fa-var-comment-slash,\n \"cloud-sun-rain\": $fa-var-cloud-sun-rain,\n \"compress\": $fa-var-compress,\n \"wheat-awn\": $fa-var-wheat-awn,\n \"wheat-alt\": $fa-var-wheat-alt,\n \"ankh\": $fa-var-ankh,\n \"hands-holding-child\": $fa-var-hands-holding-child,\n \"asterisk\": $fa-var-asterisk,\n \"square-check\": $fa-var-square-check,\n \"check-square\": $fa-var-check-square,\n \"peseta-sign\": $fa-var-peseta-sign,\n \"heading\": $fa-var-heading,\n \"header\": $fa-var-header,\n \"ghost\": $fa-var-ghost,\n \"list\": $fa-var-list,\n \"list-squares\": $fa-var-list-squares,\n \"square-phone-flip\": $fa-var-square-phone-flip,\n \"phone-square-alt\": $fa-var-phone-square-alt,\n \"cart-plus\": $fa-var-cart-plus,\n \"gamepad\": $fa-var-gamepad,\n \"circle-dot\": $fa-var-circle-dot,\n \"dot-circle\": $fa-var-dot-circle,\n \"face-dizzy\": $fa-var-face-dizzy,\n \"dizzy\": $fa-var-dizzy,\n \"egg\": $fa-var-egg,\n \"house-medical-circle-xmark\": $fa-var-house-medical-circle-xmark,\n \"campground\": $fa-var-campground,\n \"folder-plus\": $fa-var-folder-plus,\n \"futbol\": $fa-var-futbol,\n \"futbol-ball\": $fa-var-futbol-ball,\n \"soccer-ball\": $fa-var-soccer-ball,\n \"paintbrush\": $fa-var-paintbrush,\n \"paint-brush\": $fa-var-paint-brush,\n \"lock\": $fa-var-lock,\n \"gas-pump\": $fa-var-gas-pump,\n \"hot-tub-person\": $fa-var-hot-tub-person,\n \"hot-tub\": $fa-var-hot-tub,\n \"map-location\": $fa-var-map-location,\n \"map-marked\": $fa-var-map-marked,\n \"house-flood-water\": $fa-var-house-flood-water,\n \"tree\": $fa-var-tree,\n \"bridge-lock\": $fa-var-bridge-lock,\n \"sack-dollar\": $fa-var-sack-dollar,\n \"pen-to-square\": $fa-var-pen-to-square,\n \"edit\": $fa-var-edit,\n \"car-side\": $fa-var-car-side,\n \"share-nodes\": $fa-var-share-nodes,\n \"share-alt\": $fa-var-share-alt,\n \"heart-circle-minus\": $fa-var-heart-circle-minus,\n \"hourglass-half\": $fa-var-hourglass-half,\n \"hourglass-2\": $fa-var-hourglass-2,\n \"microscope\": $fa-var-microscope,\n \"sink\": $fa-var-sink,\n \"bag-shopping\": $fa-var-bag-shopping,\n \"shopping-bag\": $fa-var-shopping-bag,\n \"arrow-down-z-a\": $fa-var-arrow-down-z-a,\n \"sort-alpha-desc\": $fa-var-sort-alpha-desc,\n \"sort-alpha-down-alt\": $fa-var-sort-alpha-down-alt,\n \"mitten\": $fa-var-mitten,\n \"person-rays\": $fa-var-person-rays,\n \"users\": $fa-var-users,\n \"eye-slash\": $fa-var-eye-slash,\n \"flask-vial\": $fa-var-flask-vial,\n \"hand\": $fa-var-hand,\n \"hand-paper\": $fa-var-hand-paper,\n \"om\": $fa-var-om,\n \"worm\": $fa-var-worm,\n \"house-circle-xmark\": $fa-var-house-circle-xmark,\n \"plug\": $fa-var-plug,\n \"chevron-up\": $fa-var-chevron-up,\n \"hand-spock\": $fa-var-hand-spock,\n \"stopwatch\": $fa-var-stopwatch,\n \"face-kiss\": $fa-var-face-kiss,\n \"kiss\": $fa-var-kiss,\n \"bridge-circle-xmark\": $fa-var-bridge-circle-xmark,\n \"face-grin-tongue\": $fa-var-face-grin-tongue,\n \"grin-tongue\": $fa-var-grin-tongue,\n \"chess-bishop\": $fa-var-chess-bishop,\n \"face-grin-wink\": $fa-var-face-grin-wink,\n \"grin-wink\": $fa-var-grin-wink,\n \"ear-deaf\": $fa-var-ear-deaf,\n \"deaf\": $fa-var-deaf,\n \"deafness\": $fa-var-deafness,\n \"hard-of-hearing\": $fa-var-hard-of-hearing,\n \"road-circle-check\": $fa-var-road-circle-check,\n \"dice-five\": $fa-var-dice-five,\n \"square-rss\": $fa-var-square-rss,\n \"rss-square\": $fa-var-rss-square,\n \"land-mine-on\": $fa-var-land-mine-on,\n \"i-cursor\": $fa-var-i-cursor,\n \"stamp\": $fa-var-stamp,\n \"stairs\": $fa-var-stairs,\n \"i\": $fa-var-i,\n \"hryvnia-sign\": $fa-var-hryvnia-sign,\n \"hryvnia\": $fa-var-hryvnia,\n \"pills\": $fa-var-pills,\n \"face-grin-wide\": $fa-var-face-grin-wide,\n \"grin-alt\": $fa-var-grin-alt,\n \"tooth\": $fa-var-tooth,\n \"v\": $fa-var-v,\n \"bangladeshi-taka-sign\": $fa-var-bangladeshi-taka-sign,\n \"bicycle\": $fa-var-bicycle,\n \"staff-snake\": $fa-var-staff-snake,\n \"rod-asclepius\": $fa-var-rod-asclepius,\n \"rod-snake\": $fa-var-rod-snake,\n \"staff-aesculapius\": $fa-var-staff-aesculapius,\n \"head-side-cough-slash\": $fa-var-head-side-cough-slash,\n \"truck-medical\": $fa-var-truck-medical,\n \"ambulance\": $fa-var-ambulance,\n \"wheat-awn-circle-exclamation\": $fa-var-wheat-awn-circle-exclamation,\n \"snowman\": $fa-var-snowman,\n \"mortar-pestle\": $fa-var-mortar-pestle,\n \"road-barrier\": $fa-var-road-barrier,\n \"school\": $fa-var-school,\n \"igloo\": $fa-var-igloo,\n \"joint\": $fa-var-joint,\n \"angle-right\": $fa-var-angle-right,\n \"horse\": $fa-var-horse,\n \"q\": $fa-var-q,\n \"g\": $fa-var-g,\n \"notes-medical\": $fa-var-notes-medical,\n \"temperature-half\": $fa-var-temperature-half,\n \"temperature-2\": $fa-var-temperature-2,\n \"thermometer-2\": $fa-var-thermometer-2,\n \"thermometer-half\": $fa-var-thermometer-half,\n \"dong-sign\": $fa-var-dong-sign,\n \"capsules\": $fa-var-capsules,\n \"poo-storm\": $fa-var-poo-storm,\n \"poo-bolt\": $fa-var-poo-bolt,\n \"face-frown-open\": $fa-var-face-frown-open,\n \"frown-open\": $fa-var-frown-open,\n \"hand-point-up\": $fa-var-hand-point-up,\n \"money-bill\": $fa-var-money-bill,\n \"bookmark\": $fa-var-bookmark,\n \"align-justify\": $fa-var-align-justify,\n \"umbrella-beach\": $fa-var-umbrella-beach,\n \"helmet-un\": $fa-var-helmet-un,\n \"bullseye\": $fa-var-bullseye,\n \"bacon\": $fa-var-bacon,\n \"hand-point-down\": $fa-var-hand-point-down,\n \"arrow-up-from-bracket\": $fa-var-arrow-up-from-bracket,\n \"folder\": $fa-var-folder,\n \"folder-blank\": $fa-var-folder-blank,\n \"file-waveform\": $fa-var-file-waveform,\n \"file-medical-alt\": $fa-var-file-medical-alt,\n \"radiation\": $fa-var-radiation,\n \"chart-simple\": $fa-var-chart-simple,\n \"mars-stroke\": $fa-var-mars-stroke,\n \"vial\": $fa-var-vial,\n \"gauge\": $fa-var-gauge,\n \"dashboard\": $fa-var-dashboard,\n \"gauge-med\": $fa-var-gauge-med,\n \"tachometer-alt-average\": $fa-var-tachometer-alt-average,\n \"wand-magic-sparkles\": $fa-var-wand-magic-sparkles,\n \"magic-wand-sparkles\": $fa-var-magic-wand-sparkles,\n \"e\": $fa-var-e,\n \"pen-clip\": $fa-var-pen-clip,\n \"pen-alt\": $fa-var-pen-alt,\n \"bridge-circle-exclamation\": $fa-var-bridge-circle-exclamation,\n \"user\": $fa-var-user,\n \"school-circle-check\": $fa-var-school-circle-check,\n \"dumpster\": $fa-var-dumpster,\n \"van-shuttle\": $fa-var-van-shuttle,\n \"shuttle-van\": $fa-var-shuttle-van,\n \"building-user\": $fa-var-building-user,\n \"square-caret-left\": $fa-var-square-caret-left,\n \"caret-square-left\": $fa-var-caret-square-left,\n \"highlighter\": $fa-var-highlighter,\n \"key\": $fa-var-key,\n \"bullhorn\": $fa-var-bullhorn,\n \"globe\": $fa-var-globe,\n \"synagogue\": $fa-var-synagogue,\n \"person-half-dress\": $fa-var-person-half-dress,\n \"road-bridge\": $fa-var-road-bridge,\n \"location-arrow\": $fa-var-location-arrow,\n \"c\": $fa-var-c,\n \"tablet-button\": $fa-var-tablet-button,\n \"building-lock\": $fa-var-building-lock,\n \"pizza-slice\": $fa-var-pizza-slice,\n \"money-bill-wave\": $fa-var-money-bill-wave,\n \"chart-area\": $fa-var-chart-area,\n \"area-chart\": $fa-var-area-chart,\n \"house-flag\": $fa-var-house-flag,\n \"person-circle-minus\": $fa-var-person-circle-minus,\n \"ban\": $fa-var-ban,\n \"cancel\": $fa-var-cancel,\n \"camera-rotate\": $fa-var-camera-rotate,\n \"spray-can-sparkles\": $fa-var-spray-can-sparkles,\n \"air-freshener\": $fa-var-air-freshener,\n \"star\": $fa-var-star,\n \"repeat\": $fa-var-repeat,\n \"cross\": $fa-var-cross,\n \"box\": $fa-var-box,\n \"venus-mars\": $fa-var-venus-mars,\n \"arrow-pointer\": $fa-var-arrow-pointer,\n \"mouse-pointer\": $fa-var-mouse-pointer,\n \"maximize\": $fa-var-maximize,\n \"expand-arrows-alt\": $fa-var-expand-arrows-alt,\n \"charging-station\": $fa-var-charging-station,\n \"shapes\": $fa-var-shapes,\n \"triangle-circle-square\": $fa-var-triangle-circle-square,\n \"shuffle\": $fa-var-shuffle,\n \"random\": $fa-var-random,\n \"person-running\": $fa-var-person-running,\n \"running\": $fa-var-running,\n \"mobile-retro\": $fa-var-mobile-retro,\n \"grip-lines-vertical\": $fa-var-grip-lines-vertical,\n \"spider\": $fa-var-spider,\n \"hands-bound\": $fa-var-hands-bound,\n \"file-invoice-dollar\": $fa-var-file-invoice-dollar,\n \"plane-circle-exclamation\": $fa-var-plane-circle-exclamation,\n \"x-ray\": $fa-var-x-ray,\n \"spell-check\": $fa-var-spell-check,\n \"slash\": $fa-var-slash,\n \"computer-mouse\": $fa-var-computer-mouse,\n \"mouse\": $fa-var-mouse,\n \"arrow-right-to-bracket\": $fa-var-arrow-right-to-bracket,\n \"sign-in\": $fa-var-sign-in,\n \"shop-slash\": $fa-var-shop-slash,\n \"store-alt-slash\": $fa-var-store-alt-slash,\n \"server\": $fa-var-server,\n \"virus-covid-slash\": $fa-var-virus-covid-slash,\n \"shop-lock\": $fa-var-shop-lock,\n \"hourglass-start\": $fa-var-hourglass-start,\n \"hourglass-1\": $fa-var-hourglass-1,\n \"blender-phone\": $fa-var-blender-phone,\n \"building-wheat\": $fa-var-building-wheat,\n \"person-breastfeeding\": $fa-var-person-breastfeeding,\n \"right-to-bracket\": $fa-var-right-to-bracket,\n \"sign-in-alt\": $fa-var-sign-in-alt,\n \"venus\": $fa-var-venus,\n \"passport\": $fa-var-passport,\n \"thumbtack-slash\": $fa-var-thumbtack-slash,\n \"thumb-tack-slash\": $fa-var-thumb-tack-slash,\n \"heart-pulse\": $fa-var-heart-pulse,\n \"heartbeat\": $fa-var-heartbeat,\n \"people-carry-box\": $fa-var-people-carry-box,\n \"people-carry\": $fa-var-people-carry,\n \"temperature-high\": $fa-var-temperature-high,\n \"microchip\": $fa-var-microchip,\n \"crown\": $fa-var-crown,\n \"weight-hanging\": $fa-var-weight-hanging,\n \"xmarks-lines\": $fa-var-xmarks-lines,\n \"file-prescription\": $fa-var-file-prescription,\n \"weight-scale\": $fa-var-weight-scale,\n \"weight\": $fa-var-weight,\n \"user-group\": $fa-var-user-group,\n \"user-friends\": $fa-var-user-friends,\n \"arrow-up-a-z\": $fa-var-arrow-up-a-z,\n \"sort-alpha-up\": $fa-var-sort-alpha-up,\n \"chess-knight\": $fa-var-chess-knight,\n \"face-laugh-squint\": $fa-var-face-laugh-squint,\n \"laugh-squint\": $fa-var-laugh-squint,\n \"wheelchair\": $fa-var-wheelchair,\n \"circle-arrow-up\": $fa-var-circle-arrow-up,\n \"arrow-circle-up\": $fa-var-arrow-circle-up,\n \"toggle-on\": $fa-var-toggle-on,\n \"person-walking\": $fa-var-person-walking,\n \"walking\": $fa-var-walking,\n \"l\": $fa-var-l,\n \"fire\": $fa-var-fire,\n \"bed-pulse\": $fa-var-bed-pulse,\n \"procedures\": $fa-var-procedures,\n \"shuttle-space\": $fa-var-shuttle-space,\n \"space-shuttle\": $fa-var-space-shuttle,\n \"face-laugh\": $fa-var-face-laugh,\n \"laugh\": $fa-var-laugh,\n \"folder-open\": $fa-var-folder-open,\n \"heart-circle-plus\": $fa-var-heart-circle-plus,\n \"code-fork\": $fa-var-code-fork,\n \"city\": $fa-var-city,\n \"microphone-lines\": $fa-var-microphone-lines,\n \"microphone-alt\": $fa-var-microphone-alt,\n \"pepper-hot\": $fa-var-pepper-hot,\n \"unlock\": $fa-var-unlock,\n \"colon-sign\": $fa-var-colon-sign,\n \"headset\": $fa-var-headset,\n \"store-slash\": $fa-var-store-slash,\n \"road-circle-xmark\": $fa-var-road-circle-xmark,\n \"user-minus\": $fa-var-user-minus,\n \"mars-stroke-up\": $fa-var-mars-stroke-up,\n \"mars-stroke-v\": $fa-var-mars-stroke-v,\n \"champagne-glasses\": $fa-var-champagne-glasses,\n \"glass-cheers\": $fa-var-glass-cheers,\n \"clipboard\": $fa-var-clipboard,\n \"house-circle-exclamation\": $fa-var-house-circle-exclamation,\n \"file-arrow-up\": $fa-var-file-arrow-up,\n \"file-upload\": $fa-var-file-upload,\n \"wifi\": $fa-var-wifi,\n \"wifi-3\": $fa-var-wifi-3,\n \"wifi-strong\": $fa-var-wifi-strong,\n \"bath\": $fa-var-bath,\n \"bathtub\": $fa-var-bathtub,\n \"underline\": $fa-var-underline,\n \"user-pen\": $fa-var-user-pen,\n \"user-edit\": $fa-var-user-edit,\n \"signature\": $fa-var-signature,\n \"stroopwafel\": $fa-var-stroopwafel,\n \"bold\": $fa-var-bold,\n \"anchor-lock\": $fa-var-anchor-lock,\n \"building-ngo\": $fa-var-building-ngo,\n \"manat-sign\": $fa-var-manat-sign,\n \"not-equal\": $fa-var-not-equal,\n \"border-top-left\": $fa-var-border-top-left,\n \"border-style\": $fa-var-border-style,\n \"map-location-dot\": $fa-var-map-location-dot,\n \"map-marked-alt\": $fa-var-map-marked-alt,\n \"jedi\": $fa-var-jedi,\n \"square-poll-vertical\": $fa-var-square-poll-vertical,\n \"poll\": $fa-var-poll,\n \"mug-hot\": $fa-var-mug-hot,\n \"car-battery\": $fa-var-car-battery,\n \"battery-car\": $fa-var-battery-car,\n \"gift\": $fa-var-gift,\n \"dice-two\": $fa-var-dice-two,\n \"chess-queen\": $fa-var-chess-queen,\n \"glasses\": $fa-var-glasses,\n \"chess-board\": $fa-var-chess-board,\n \"building-circle-check\": $fa-var-building-circle-check,\n \"person-chalkboard\": $fa-var-person-chalkboard,\n \"mars-stroke-right\": $fa-var-mars-stroke-right,\n \"mars-stroke-h\": $fa-var-mars-stroke-h,\n \"hand-back-fist\": $fa-var-hand-back-fist,\n \"hand-rock\": $fa-var-hand-rock,\n \"square-caret-up\": $fa-var-square-caret-up,\n \"caret-square-up\": $fa-var-caret-square-up,\n \"cloud-showers-water\": $fa-var-cloud-showers-water,\n \"chart-bar\": $fa-var-chart-bar,\n \"bar-chart\": $fa-var-bar-chart,\n \"hands-bubbles\": $fa-var-hands-bubbles,\n \"hands-wash\": $fa-var-hands-wash,\n \"less-than-equal\": $fa-var-less-than-equal,\n \"train\": $fa-var-train,\n \"eye-low-vision\": $fa-var-eye-low-vision,\n \"low-vision\": $fa-var-low-vision,\n \"crow\": $fa-var-crow,\n \"sailboat\": $fa-var-sailboat,\n \"window-restore\": $fa-var-window-restore,\n \"square-plus\": $fa-var-square-plus,\n \"plus-square\": $fa-var-plus-square,\n \"torii-gate\": $fa-var-torii-gate,\n \"frog\": $fa-var-frog,\n \"bucket\": $fa-var-bucket,\n \"image\": $fa-var-image,\n \"microphone\": $fa-var-microphone,\n \"cow\": $fa-var-cow,\n \"caret-up\": $fa-var-caret-up,\n \"screwdriver\": $fa-var-screwdriver,\n \"folder-closed\": $fa-var-folder-closed,\n \"house-tsunami\": $fa-var-house-tsunami,\n \"square-nfi\": $fa-var-square-nfi,\n \"arrow-up-from-ground-water\": $fa-var-arrow-up-from-ground-water,\n \"martini-glass\": $fa-var-martini-glass,\n \"glass-martini-alt\": $fa-var-glass-martini-alt,\n \"square-binary\": $fa-var-square-binary,\n \"rotate-left\": $fa-var-rotate-left,\n \"rotate-back\": $fa-var-rotate-back,\n \"rotate-backward\": $fa-var-rotate-backward,\n \"undo-alt\": $fa-var-undo-alt,\n \"table-columns\": $fa-var-table-columns,\n \"columns\": $fa-var-columns,\n \"lemon\": $fa-var-lemon,\n \"head-side-mask\": $fa-var-head-side-mask,\n \"handshake\": $fa-var-handshake,\n \"gem\": $fa-var-gem,\n \"dolly\": $fa-var-dolly,\n \"dolly-box\": $fa-var-dolly-box,\n \"smoking\": $fa-var-smoking,\n \"minimize\": $fa-var-minimize,\n \"compress-arrows-alt\": $fa-var-compress-arrows-alt,\n \"monument\": $fa-var-monument,\n \"snowplow\": $fa-var-snowplow,\n \"angles-right\": $fa-var-angles-right,\n \"angle-double-right\": $fa-var-angle-double-right,\n \"cannabis\": $fa-var-cannabis,\n \"circle-play\": $fa-var-circle-play,\n \"play-circle\": $fa-var-play-circle,\n \"tablets\": $fa-var-tablets,\n \"ethernet\": $fa-var-ethernet,\n \"euro-sign\": $fa-var-euro-sign,\n \"eur\": $fa-var-eur,\n \"euro\": $fa-var-euro,\n \"chair\": $fa-var-chair,\n \"circle-check\": $fa-var-circle-check,\n \"check-circle\": $fa-var-check-circle,\n \"circle-stop\": $fa-var-circle-stop,\n \"stop-circle\": $fa-var-stop-circle,\n \"compass-drafting\": $fa-var-compass-drafting,\n \"drafting-compass\": $fa-var-drafting-compass,\n \"plate-wheat\": $fa-var-plate-wheat,\n \"icicles\": $fa-var-icicles,\n \"person-shelter\": $fa-var-person-shelter,\n \"neuter\": $fa-var-neuter,\n \"id-badge\": $fa-var-id-badge,\n \"marker\": $fa-var-marker,\n \"face-laugh-beam\": $fa-var-face-laugh-beam,\n \"laugh-beam\": $fa-var-laugh-beam,\n \"helicopter-symbol\": $fa-var-helicopter-symbol,\n \"universal-access\": $fa-var-universal-access,\n \"circle-chevron-up\": $fa-var-circle-chevron-up,\n \"chevron-circle-up\": $fa-var-chevron-circle-up,\n \"lari-sign\": $fa-var-lari-sign,\n \"volcano\": $fa-var-volcano,\n \"person-walking-dashed-line-arrow-right\": $fa-var-person-walking-dashed-line-arrow-right,\n \"sterling-sign\": $fa-var-sterling-sign,\n \"gbp\": $fa-var-gbp,\n \"pound-sign\": $fa-var-pound-sign,\n \"viruses\": $fa-var-viruses,\n \"square-person-confined\": $fa-var-square-person-confined,\n \"user-tie\": $fa-var-user-tie,\n \"arrow-down-long\": $fa-var-arrow-down-long,\n \"long-arrow-down\": $fa-var-long-arrow-down,\n \"tent-arrow-down-to-line\": $fa-var-tent-arrow-down-to-line,\n \"certificate\": $fa-var-certificate,\n \"reply-all\": $fa-var-reply-all,\n \"mail-reply-all\": $fa-var-mail-reply-all,\n \"suitcase\": $fa-var-suitcase,\n \"person-skating\": $fa-var-person-skating,\n \"skating\": $fa-var-skating,\n \"filter-circle-dollar\": $fa-var-filter-circle-dollar,\n \"funnel-dollar\": $fa-var-funnel-dollar,\n \"camera-retro\": $fa-var-camera-retro,\n \"circle-arrow-down\": $fa-var-circle-arrow-down,\n \"arrow-circle-down\": $fa-var-arrow-circle-down,\n \"file-import\": $fa-var-file-import,\n \"arrow-right-to-file\": $fa-var-arrow-right-to-file,\n \"square-arrow-up-right\": $fa-var-square-arrow-up-right,\n \"external-link-square\": $fa-var-external-link-square,\n \"box-open\": $fa-var-box-open,\n \"scroll\": $fa-var-scroll,\n \"spa\": $fa-var-spa,\n \"location-pin-lock\": $fa-var-location-pin-lock,\n \"pause\": $fa-var-pause,\n \"hill-avalanche\": $fa-var-hill-avalanche,\n \"temperature-empty\": $fa-var-temperature-empty,\n \"temperature-0\": $fa-var-temperature-0,\n \"thermometer-0\": $fa-var-thermometer-0,\n \"thermometer-empty\": $fa-var-thermometer-empty,\n \"bomb\": $fa-var-bomb,\n \"registered\": $fa-var-registered,\n \"address-card\": $fa-var-address-card,\n \"contact-card\": $fa-var-contact-card,\n \"vcard\": $fa-var-vcard,\n \"scale-unbalanced-flip\": $fa-var-scale-unbalanced-flip,\n \"balance-scale-right\": $fa-var-balance-scale-right,\n \"subscript\": $fa-var-subscript,\n \"diamond-turn-right\": $fa-var-diamond-turn-right,\n \"directions\": $fa-var-directions,\n \"burst\": $fa-var-burst,\n \"house-laptop\": $fa-var-house-laptop,\n \"laptop-house\": $fa-var-laptop-house,\n \"face-tired\": $fa-var-face-tired,\n \"tired\": $fa-var-tired,\n \"money-bills\": $fa-var-money-bills,\n \"smog\": $fa-var-smog,\n \"crutch\": $fa-var-crutch,\n \"cloud-arrow-up\": $fa-var-cloud-arrow-up,\n \"cloud-upload\": $fa-var-cloud-upload,\n \"cloud-upload-alt\": $fa-var-cloud-upload-alt,\n \"palette\": $fa-var-palette,\n \"arrows-turn-right\": $fa-var-arrows-turn-right,\n \"vest\": $fa-var-vest,\n \"ferry\": $fa-var-ferry,\n \"arrows-down-to-people\": $fa-var-arrows-down-to-people,\n \"seedling\": $fa-var-seedling,\n \"sprout\": $fa-var-sprout,\n \"left-right\": $fa-var-left-right,\n \"arrows-alt-h\": $fa-var-arrows-alt-h,\n \"boxes-packing\": $fa-var-boxes-packing,\n \"circle-arrow-left\": $fa-var-circle-arrow-left,\n \"arrow-circle-left\": $fa-var-arrow-circle-left,\n \"group-arrows-rotate\": $fa-var-group-arrows-rotate,\n \"bowl-food\": $fa-var-bowl-food,\n \"candy-cane\": $fa-var-candy-cane,\n \"arrow-down-wide-short\": $fa-var-arrow-down-wide-short,\n \"sort-amount-asc\": $fa-var-sort-amount-asc,\n \"sort-amount-down\": $fa-var-sort-amount-down,\n \"cloud-bolt\": $fa-var-cloud-bolt,\n \"thunderstorm\": $fa-var-thunderstorm,\n \"text-slash\": $fa-var-text-slash,\n \"remove-format\": $fa-var-remove-format,\n \"face-smile-wink\": $fa-var-face-smile-wink,\n \"smile-wink\": $fa-var-smile-wink,\n \"file-word\": $fa-var-file-word,\n \"file-powerpoint\": $fa-var-file-powerpoint,\n \"arrows-left-right\": $fa-var-arrows-left-right,\n \"arrows-h\": $fa-var-arrows-h,\n \"house-lock\": $fa-var-house-lock,\n \"cloud-arrow-down\": $fa-var-cloud-arrow-down,\n \"cloud-download\": $fa-var-cloud-download,\n \"cloud-download-alt\": $fa-var-cloud-download-alt,\n \"children\": $fa-var-children,\n \"chalkboard\": $fa-var-chalkboard,\n \"blackboard\": $fa-var-blackboard,\n \"user-large-slash\": $fa-var-user-large-slash,\n \"user-alt-slash\": $fa-var-user-alt-slash,\n \"envelope-open\": $fa-var-envelope-open,\n \"handshake-simple-slash\": $fa-var-handshake-simple-slash,\n \"handshake-alt-slash\": $fa-var-handshake-alt-slash,\n \"mattress-pillow\": $fa-var-mattress-pillow,\n \"guarani-sign\": $fa-var-guarani-sign,\n \"arrows-rotate\": $fa-var-arrows-rotate,\n \"refresh\": $fa-var-refresh,\n \"sync\": $fa-var-sync,\n \"fire-extinguisher\": $fa-var-fire-extinguisher,\n \"cruzeiro-sign\": $fa-var-cruzeiro-sign,\n \"greater-than-equal\": $fa-var-greater-than-equal,\n \"shield-halved\": $fa-var-shield-halved,\n \"shield-alt\": $fa-var-shield-alt,\n \"book-atlas\": $fa-var-book-atlas,\n \"atlas\": $fa-var-atlas,\n \"virus\": $fa-var-virus,\n \"envelope-circle-check\": $fa-var-envelope-circle-check,\n \"layer-group\": $fa-var-layer-group,\n \"arrows-to-dot\": $fa-var-arrows-to-dot,\n \"archway\": $fa-var-archway,\n \"heart-circle-check\": $fa-var-heart-circle-check,\n \"house-chimney-crack\": $fa-var-house-chimney-crack,\n \"house-damage\": $fa-var-house-damage,\n \"file-zipper\": $fa-var-file-zipper,\n \"file-archive\": $fa-var-file-archive,\n \"square\": $fa-var-square,\n \"martini-glass-empty\": $fa-var-martini-glass-empty,\n \"glass-martini\": $fa-var-glass-martini,\n \"couch\": $fa-var-couch,\n \"cedi-sign\": $fa-var-cedi-sign,\n \"italic\": $fa-var-italic,\n \"table-cells-column-lock\": $fa-var-table-cells-column-lock,\n \"church\": $fa-var-church,\n \"comments-dollar\": $fa-var-comments-dollar,\n \"democrat\": $fa-var-democrat,\n \"z\": $fa-var-z,\n \"person-skiing\": $fa-var-person-skiing,\n \"skiing\": $fa-var-skiing,\n \"road-lock\": $fa-var-road-lock,\n \"a\": $fa-var-a,\n \"temperature-arrow-down\": $fa-var-temperature-arrow-down,\n \"temperature-down\": $fa-var-temperature-down,\n \"feather-pointed\": $fa-var-feather-pointed,\n \"feather-alt\": $fa-var-feather-alt,\n \"p\": $fa-var-p,\n \"snowflake\": $fa-var-snowflake,\n \"newspaper\": $fa-var-newspaper,\n \"rectangle-ad\": $fa-var-rectangle-ad,\n \"ad\": $fa-var-ad,\n \"circle-arrow-right\": $fa-var-circle-arrow-right,\n \"arrow-circle-right\": $fa-var-arrow-circle-right,\n \"filter-circle-xmark\": $fa-var-filter-circle-xmark,\n \"locust\": $fa-var-locust,\n \"sort\": $fa-var-sort,\n \"unsorted\": $fa-var-unsorted,\n \"list-ol\": $fa-var-list-ol,\n \"list-1-2\": $fa-var-list-1-2,\n \"list-numeric\": $fa-var-list-numeric,\n \"person-dress-burst\": $fa-var-person-dress-burst,\n \"money-check-dollar\": $fa-var-money-check-dollar,\n \"money-check-alt\": $fa-var-money-check-alt,\n \"vector-square\": $fa-var-vector-square,\n \"bread-slice\": $fa-var-bread-slice,\n \"language\": $fa-var-language,\n \"face-kiss-wink-heart\": $fa-var-face-kiss-wink-heart,\n \"kiss-wink-heart\": $fa-var-kiss-wink-heart,\n \"filter\": $fa-var-filter,\n \"question\": $fa-var-question,\n \"file-signature\": $fa-var-file-signature,\n \"up-down-left-right\": $fa-var-up-down-left-right,\n \"arrows-alt\": $fa-var-arrows-alt,\n \"house-chimney-user\": $fa-var-house-chimney-user,\n \"hand-holding-heart\": $fa-var-hand-holding-heart,\n \"puzzle-piece\": $fa-var-puzzle-piece,\n \"money-check\": $fa-var-money-check,\n \"star-half-stroke\": $fa-var-star-half-stroke,\n \"star-half-alt\": $fa-var-star-half-alt,\n \"code\": $fa-var-code,\n \"whiskey-glass\": $fa-var-whiskey-glass,\n \"glass-whiskey\": $fa-var-glass-whiskey,\n \"building-circle-exclamation\": $fa-var-building-circle-exclamation,\n \"magnifying-glass-chart\": $fa-var-magnifying-glass-chart,\n \"arrow-up-right-from-square\": $fa-var-arrow-up-right-from-square,\n \"external-link\": $fa-var-external-link,\n \"cubes-stacked\": $fa-var-cubes-stacked,\n \"won-sign\": $fa-var-won-sign,\n \"krw\": $fa-var-krw,\n \"won\": $fa-var-won,\n \"virus-covid\": $fa-var-virus-covid,\n \"austral-sign\": $fa-var-austral-sign,\n \"f\": $fa-var-f,\n \"leaf\": $fa-var-leaf,\n \"road\": $fa-var-road,\n \"taxi\": $fa-var-taxi,\n \"cab\": $fa-var-cab,\n \"person-circle-plus\": $fa-var-person-circle-plus,\n \"chart-pie\": $fa-var-chart-pie,\n \"pie-chart\": $fa-var-pie-chart,\n \"bolt-lightning\": $fa-var-bolt-lightning,\n \"sack-xmark\": $fa-var-sack-xmark,\n \"file-excel\": $fa-var-file-excel,\n \"file-contract\": $fa-var-file-contract,\n \"fish-fins\": $fa-var-fish-fins,\n \"building-flag\": $fa-var-building-flag,\n \"face-grin-beam\": $fa-var-face-grin-beam,\n \"grin-beam\": $fa-var-grin-beam,\n \"object-ungroup\": $fa-var-object-ungroup,\n \"poop\": $fa-var-poop,\n \"location-pin\": $fa-var-location-pin,\n \"map-marker\": $fa-var-map-marker,\n \"kaaba\": $fa-var-kaaba,\n \"toilet-paper\": $fa-var-toilet-paper,\n \"helmet-safety\": $fa-var-helmet-safety,\n \"hard-hat\": $fa-var-hard-hat,\n \"hat-hard\": $fa-var-hat-hard,\n \"eject\": $fa-var-eject,\n \"circle-right\": $fa-var-circle-right,\n \"arrow-alt-circle-right\": $fa-var-arrow-alt-circle-right,\n \"plane-circle-check\": $fa-var-plane-circle-check,\n \"face-rolling-eyes\": $fa-var-face-rolling-eyes,\n \"meh-rolling-eyes\": $fa-var-meh-rolling-eyes,\n \"object-group\": $fa-var-object-group,\n \"chart-line\": $fa-var-chart-line,\n \"line-chart\": $fa-var-line-chart,\n \"mask-ventilator\": $fa-var-mask-ventilator,\n \"arrow-right\": $fa-var-arrow-right,\n \"signs-post\": $fa-var-signs-post,\n \"map-signs\": $fa-var-map-signs,\n \"cash-register\": $fa-var-cash-register,\n \"person-circle-question\": $fa-var-person-circle-question,\n \"h\": $fa-var-h,\n \"tarp\": $fa-var-tarp,\n \"screwdriver-wrench\": $fa-var-screwdriver-wrench,\n \"tools\": $fa-var-tools,\n \"arrows-to-eye\": $fa-var-arrows-to-eye,\n \"plug-circle-bolt\": $fa-var-plug-circle-bolt,\n \"heart\": $fa-var-heart,\n \"mars-and-venus\": $fa-var-mars-and-venus,\n \"house-user\": $fa-var-house-user,\n \"home-user\": $fa-var-home-user,\n \"dumpster-fire\": $fa-var-dumpster-fire,\n \"house-crack\": $fa-var-house-crack,\n \"martini-glass-citrus\": $fa-var-martini-glass-citrus,\n \"cocktail\": $fa-var-cocktail,\n \"face-surprise\": $fa-var-face-surprise,\n \"surprise\": $fa-var-surprise,\n \"bottle-water\": $fa-var-bottle-water,\n \"circle-pause\": $fa-var-circle-pause,\n \"pause-circle\": $fa-var-pause-circle,\n \"toilet-paper-slash\": $fa-var-toilet-paper-slash,\n \"apple-whole\": $fa-var-apple-whole,\n \"apple-alt\": $fa-var-apple-alt,\n \"kitchen-set\": $fa-var-kitchen-set,\n \"r\": $fa-var-r,\n \"temperature-quarter\": $fa-var-temperature-quarter,\n \"temperature-1\": $fa-var-temperature-1,\n \"thermometer-1\": $fa-var-thermometer-1,\n \"thermometer-quarter\": $fa-var-thermometer-quarter,\n \"cube\": $fa-var-cube,\n \"bitcoin-sign\": $fa-var-bitcoin-sign,\n \"shield-dog\": $fa-var-shield-dog,\n \"solar-panel\": $fa-var-solar-panel,\n \"lock-open\": $fa-var-lock-open,\n \"elevator\": $fa-var-elevator,\n \"money-bill-transfer\": $fa-var-money-bill-transfer,\n \"money-bill-trend-up\": $fa-var-money-bill-trend-up,\n \"house-flood-water-circle-arrow-right\": $fa-var-house-flood-water-circle-arrow-right,\n \"square-poll-horizontal\": $fa-var-square-poll-horizontal,\n \"poll-h\": $fa-var-poll-h,\n \"circle\": $fa-var-circle,\n \"backward-fast\": $fa-var-backward-fast,\n \"fast-backward\": $fa-var-fast-backward,\n \"recycle\": $fa-var-recycle,\n \"user-astronaut\": $fa-var-user-astronaut,\n \"plane-slash\": $fa-var-plane-slash,\n \"trademark\": $fa-var-trademark,\n \"basketball\": $fa-var-basketball,\n \"basketball-ball\": $fa-var-basketball-ball,\n \"satellite-dish\": $fa-var-satellite-dish,\n \"circle-up\": $fa-var-circle-up,\n \"arrow-alt-circle-up\": $fa-var-arrow-alt-circle-up,\n \"mobile-screen-button\": $fa-var-mobile-screen-button,\n \"mobile-alt\": $fa-var-mobile-alt,\n \"volume-high\": $fa-var-volume-high,\n \"volume-up\": $fa-var-volume-up,\n \"users-rays\": $fa-var-users-rays,\n \"wallet\": $fa-var-wallet,\n \"clipboard-check\": $fa-var-clipboard-check,\n \"file-audio\": $fa-var-file-audio,\n \"burger\": $fa-var-burger,\n \"hamburger\": $fa-var-hamburger,\n \"wrench\": $fa-var-wrench,\n \"bugs\": $fa-var-bugs,\n \"rupee-sign\": $fa-var-rupee-sign,\n \"rupee\": $fa-var-rupee,\n \"file-image\": $fa-var-file-image,\n \"circle-question\": $fa-var-circle-question,\n \"question-circle\": $fa-var-question-circle,\n \"plane-departure\": $fa-var-plane-departure,\n \"handshake-slash\": $fa-var-handshake-slash,\n \"book-bookmark\": $fa-var-book-bookmark,\n \"code-branch\": $fa-var-code-branch,\n \"hat-cowboy\": $fa-var-hat-cowboy,\n \"bridge\": $fa-var-bridge,\n \"phone-flip\": $fa-var-phone-flip,\n \"phone-alt\": $fa-var-phone-alt,\n \"truck-front\": $fa-var-truck-front,\n \"cat\": $fa-var-cat,\n \"anchor-circle-exclamation\": $fa-var-anchor-circle-exclamation,\n \"truck-field\": $fa-var-truck-field,\n \"route\": $fa-var-route,\n \"clipboard-question\": $fa-var-clipboard-question,\n \"panorama\": $fa-var-panorama,\n \"comment-medical\": $fa-var-comment-medical,\n \"teeth-open\": $fa-var-teeth-open,\n \"file-circle-minus\": $fa-var-file-circle-minus,\n \"tags\": $fa-var-tags,\n \"wine-glass\": $fa-var-wine-glass,\n \"forward-fast\": $fa-var-forward-fast,\n \"fast-forward\": $fa-var-fast-forward,\n \"face-meh-blank\": $fa-var-face-meh-blank,\n \"meh-blank\": $fa-var-meh-blank,\n \"square-parking\": $fa-var-square-parking,\n \"parking\": $fa-var-parking,\n \"house-signal\": $fa-var-house-signal,\n \"bars-progress\": $fa-var-bars-progress,\n \"tasks-alt\": $fa-var-tasks-alt,\n \"faucet-drip\": $fa-var-faucet-drip,\n \"cart-flatbed\": $fa-var-cart-flatbed,\n \"dolly-flatbed\": $fa-var-dolly-flatbed,\n \"ban-smoking\": $fa-var-ban-smoking,\n \"smoking-ban\": $fa-var-smoking-ban,\n \"terminal\": $fa-var-terminal,\n \"mobile-button\": $fa-var-mobile-button,\n \"house-medical-flag\": $fa-var-house-medical-flag,\n \"basket-shopping\": $fa-var-basket-shopping,\n \"shopping-basket\": $fa-var-shopping-basket,\n \"tape\": $fa-var-tape,\n \"bus-simple\": $fa-var-bus-simple,\n \"bus-alt\": $fa-var-bus-alt,\n \"eye\": $fa-var-eye,\n \"face-sad-cry\": $fa-var-face-sad-cry,\n \"sad-cry\": $fa-var-sad-cry,\n \"audio-description\": $fa-var-audio-description,\n \"person-military-to-person\": $fa-var-person-military-to-person,\n \"file-shield\": $fa-var-file-shield,\n \"user-slash\": $fa-var-user-slash,\n \"pen\": $fa-var-pen,\n \"tower-observation\": $fa-var-tower-observation,\n \"file-code\": $fa-var-file-code,\n \"signal\": $fa-var-signal,\n \"signal-5\": $fa-var-signal-5,\n \"signal-perfect\": $fa-var-signal-perfect,\n \"bus\": $fa-var-bus,\n \"heart-circle-xmark\": $fa-var-heart-circle-xmark,\n \"house-chimney\": $fa-var-house-chimney,\n \"home-lg\": $fa-var-home-lg,\n \"window-maximize\": $fa-var-window-maximize,\n \"face-frown\": $fa-var-face-frown,\n \"frown\": $fa-var-frown,\n \"prescription\": $fa-var-prescription,\n \"shop\": $fa-var-shop,\n \"store-alt\": $fa-var-store-alt,\n \"floppy-disk\": $fa-var-floppy-disk,\n \"save\": $fa-var-save,\n \"vihara\": $fa-var-vihara,\n \"scale-unbalanced\": $fa-var-scale-unbalanced,\n \"balance-scale-left\": $fa-var-balance-scale-left,\n \"sort-up\": $fa-var-sort-up,\n \"sort-asc\": $fa-var-sort-asc,\n \"comment-dots\": $fa-var-comment-dots,\n \"commenting\": $fa-var-commenting,\n \"plant-wilt\": $fa-var-plant-wilt,\n \"diamond\": $fa-var-diamond,\n \"face-grin-squint\": $fa-var-face-grin-squint,\n \"grin-squint\": $fa-var-grin-squint,\n \"hand-holding-dollar\": $fa-var-hand-holding-dollar,\n \"hand-holding-usd\": $fa-var-hand-holding-usd,\n \"chart-diagram\": $fa-var-chart-diagram,\n \"bacterium\": $fa-var-bacterium,\n \"hand-pointer\": $fa-var-hand-pointer,\n \"drum-steelpan\": $fa-var-drum-steelpan,\n \"hand-scissors\": $fa-var-hand-scissors,\n \"hands-praying\": $fa-var-hands-praying,\n \"praying-hands\": $fa-var-praying-hands,\n \"arrow-rotate-right\": $fa-var-arrow-rotate-right,\n \"arrow-right-rotate\": $fa-var-arrow-right-rotate,\n \"arrow-rotate-forward\": $fa-var-arrow-rotate-forward,\n \"redo\": $fa-var-redo,\n \"biohazard\": $fa-var-biohazard,\n \"location-crosshairs\": $fa-var-location-crosshairs,\n \"location\": $fa-var-location,\n \"mars-double\": $fa-var-mars-double,\n \"child-dress\": $fa-var-child-dress,\n \"users-between-lines\": $fa-var-users-between-lines,\n \"lungs-virus\": $fa-var-lungs-virus,\n \"face-grin-tears\": $fa-var-face-grin-tears,\n \"grin-tears\": $fa-var-grin-tears,\n \"phone\": $fa-var-phone,\n \"calendar-xmark\": $fa-var-calendar-xmark,\n \"calendar-times\": $fa-var-calendar-times,\n \"child-reaching\": $fa-var-child-reaching,\n \"head-side-virus\": $fa-var-head-side-virus,\n \"user-gear\": $fa-var-user-gear,\n \"user-cog\": $fa-var-user-cog,\n \"arrow-up-1-9\": $fa-var-arrow-up-1-9,\n \"sort-numeric-up\": $fa-var-sort-numeric-up,\n \"door-closed\": $fa-var-door-closed,\n \"shield-virus\": $fa-var-shield-virus,\n \"dice-six\": $fa-var-dice-six,\n \"mosquito-net\": $fa-var-mosquito-net,\n \"file-fragment\": $fa-var-file-fragment,\n \"bridge-water\": $fa-var-bridge-water,\n \"person-booth\": $fa-var-person-booth,\n \"text-width\": $fa-var-text-width,\n \"hat-wizard\": $fa-var-hat-wizard,\n \"pen-fancy\": $fa-var-pen-fancy,\n \"person-digging\": $fa-var-person-digging,\n \"digging\": $fa-var-digging,\n \"trash\": $fa-var-trash,\n \"gauge-simple\": $fa-var-gauge-simple,\n \"gauge-simple-med\": $fa-var-gauge-simple-med,\n \"tachometer-average\": $fa-var-tachometer-average,\n \"book-medical\": $fa-var-book-medical,\n \"poo\": $fa-var-poo,\n \"quote-right\": $fa-var-quote-right,\n \"quote-right-alt\": $fa-var-quote-right-alt,\n \"shirt\": $fa-var-shirt,\n \"t-shirt\": $fa-var-t-shirt,\n \"tshirt\": $fa-var-tshirt,\n \"cubes\": $fa-var-cubes,\n \"divide\": $fa-var-divide,\n \"tenge-sign\": $fa-var-tenge-sign,\n \"tenge\": $fa-var-tenge,\n \"headphones\": $fa-var-headphones,\n \"hands-holding\": $fa-var-hands-holding,\n \"hands-clapping\": $fa-var-hands-clapping,\n \"republican\": $fa-var-republican,\n \"arrow-left\": $fa-var-arrow-left,\n \"person-circle-xmark\": $fa-var-person-circle-xmark,\n \"ruler\": $fa-var-ruler,\n \"align-left\": $fa-var-align-left,\n \"dice-d6\": $fa-var-dice-d6,\n \"restroom\": $fa-var-restroom,\n \"j\": $fa-var-j,\n \"users-viewfinder\": $fa-var-users-viewfinder,\n \"file-video\": $fa-var-file-video,\n \"up-right-from-square\": $fa-var-up-right-from-square,\n \"external-link-alt\": $fa-var-external-link-alt,\n \"table-cells\": $fa-var-table-cells,\n \"th\": $fa-var-th,\n \"file-pdf\": $fa-var-file-pdf,\n \"book-bible\": $fa-var-book-bible,\n \"bible\": $fa-var-bible,\n \"o\": $fa-var-o,\n \"suitcase-medical\": $fa-var-suitcase-medical,\n \"medkit\": $fa-var-medkit,\n \"user-secret\": $fa-var-user-secret,\n \"otter\": $fa-var-otter,\n \"person-dress\": $fa-var-person-dress,\n \"female\": $fa-var-female,\n \"comment-dollar\": $fa-var-comment-dollar,\n \"business-time\": $fa-var-business-time,\n \"briefcase-clock\": $fa-var-briefcase-clock,\n \"table-cells-large\": $fa-var-table-cells-large,\n \"th-large\": $fa-var-th-large,\n \"book-tanakh\": $fa-var-book-tanakh,\n \"tanakh\": $fa-var-tanakh,\n \"phone-volume\": $fa-var-phone-volume,\n \"volume-control-phone\": $fa-var-volume-control-phone,\n \"hat-cowboy-side\": $fa-var-hat-cowboy-side,\n \"clipboard-user\": $fa-var-clipboard-user,\n \"child\": $fa-var-child,\n \"lira-sign\": $fa-var-lira-sign,\n \"satellite\": $fa-var-satellite,\n \"plane-lock\": $fa-var-plane-lock,\n \"tag\": $fa-var-tag,\n \"comment\": $fa-var-comment,\n \"cake-candles\": $fa-var-cake-candles,\n \"birthday-cake\": $fa-var-birthday-cake,\n \"cake\": $fa-var-cake,\n \"envelope\": $fa-var-envelope,\n \"angles-up\": $fa-var-angles-up,\n \"angle-double-up\": $fa-var-angle-double-up,\n \"paperclip\": $fa-var-paperclip,\n \"arrow-right-to-city\": $fa-var-arrow-right-to-city,\n \"ribbon\": $fa-var-ribbon,\n \"lungs\": $fa-var-lungs,\n \"arrow-up-9-1\": $fa-var-arrow-up-9-1,\n \"sort-numeric-up-alt\": $fa-var-sort-numeric-up-alt,\n \"litecoin-sign\": $fa-var-litecoin-sign,\n \"border-none\": $fa-var-border-none,\n \"circle-nodes\": $fa-var-circle-nodes,\n \"parachute-box\": $fa-var-parachute-box,\n \"indent\": $fa-var-indent,\n \"truck-field-un\": $fa-var-truck-field-un,\n \"hourglass\": $fa-var-hourglass,\n \"hourglass-empty\": $fa-var-hourglass-empty,\n \"mountain\": $fa-var-mountain,\n \"user-doctor\": $fa-var-user-doctor,\n \"user-md\": $fa-var-user-md,\n \"circle-info\": $fa-var-circle-info,\n \"info-circle\": $fa-var-info-circle,\n \"cloud-meatball\": $fa-var-cloud-meatball,\n \"camera\": $fa-var-camera,\n \"camera-alt\": $fa-var-camera-alt,\n \"square-virus\": $fa-var-square-virus,\n \"meteor\": $fa-var-meteor,\n \"car-on\": $fa-var-car-on,\n \"sleigh\": $fa-var-sleigh,\n \"arrow-down-1-9\": $fa-var-arrow-down-1-9,\n \"sort-numeric-asc\": $fa-var-sort-numeric-asc,\n \"sort-numeric-down\": $fa-var-sort-numeric-down,\n \"hand-holding-droplet\": $fa-var-hand-holding-droplet,\n \"hand-holding-water\": $fa-var-hand-holding-water,\n \"water\": $fa-var-water,\n \"calendar-check\": $fa-var-calendar-check,\n \"braille\": $fa-var-braille,\n \"prescription-bottle-medical\": $fa-var-prescription-bottle-medical,\n \"prescription-bottle-alt\": $fa-var-prescription-bottle-alt,\n \"landmark\": $fa-var-landmark,\n \"truck\": $fa-var-truck,\n \"crosshairs\": $fa-var-crosshairs,\n \"person-cane\": $fa-var-person-cane,\n \"tent\": $fa-var-tent,\n \"vest-patches\": $fa-var-vest-patches,\n \"check-double\": $fa-var-check-double,\n \"arrow-down-a-z\": $fa-var-arrow-down-a-z,\n \"sort-alpha-asc\": $fa-var-sort-alpha-asc,\n \"sort-alpha-down\": $fa-var-sort-alpha-down,\n \"money-bill-wheat\": $fa-var-money-bill-wheat,\n \"cookie\": $fa-var-cookie,\n \"arrow-rotate-left\": $fa-var-arrow-rotate-left,\n \"arrow-left-rotate\": $fa-var-arrow-left-rotate,\n \"arrow-rotate-back\": $fa-var-arrow-rotate-back,\n \"arrow-rotate-backward\": $fa-var-arrow-rotate-backward,\n \"undo\": $fa-var-undo,\n \"hard-drive\": $fa-var-hard-drive,\n \"hdd\": $fa-var-hdd,\n \"face-grin-squint-tears\": $fa-var-face-grin-squint-tears,\n \"grin-squint-tears\": $fa-var-grin-squint-tears,\n \"dumbbell\": $fa-var-dumbbell,\n \"rectangle-list\": $fa-var-rectangle-list,\n \"list-alt\": $fa-var-list-alt,\n \"tarp-droplet\": $fa-var-tarp-droplet,\n \"house-medical-circle-check\": $fa-var-house-medical-circle-check,\n \"person-skiing-nordic\": $fa-var-person-skiing-nordic,\n \"skiing-nordic\": $fa-var-skiing-nordic,\n \"calendar-plus\": $fa-var-calendar-plus,\n \"plane-arrival\": $fa-var-plane-arrival,\n \"circle-left\": $fa-var-circle-left,\n \"arrow-alt-circle-left\": $fa-var-arrow-alt-circle-left,\n \"train-subway\": $fa-var-train-subway,\n \"subway\": $fa-var-subway,\n \"chart-gantt\": $fa-var-chart-gantt,\n \"indian-rupee-sign\": $fa-var-indian-rupee-sign,\n \"indian-rupee\": $fa-var-indian-rupee,\n \"inr\": $fa-var-inr,\n \"crop-simple\": $fa-var-crop-simple,\n \"crop-alt\": $fa-var-crop-alt,\n \"money-bill-1\": $fa-var-money-bill-1,\n \"money-bill-alt\": $fa-var-money-bill-alt,\n \"left-long\": $fa-var-left-long,\n \"long-arrow-alt-left\": $fa-var-long-arrow-alt-left,\n \"dna\": $fa-var-dna,\n \"virus-slash\": $fa-var-virus-slash,\n \"minus\": $fa-var-minus,\n \"subtract\": $fa-var-subtract,\n \"chess\": $fa-var-chess,\n \"arrow-left-long\": $fa-var-arrow-left-long,\n \"long-arrow-left\": $fa-var-long-arrow-left,\n \"plug-circle-check\": $fa-var-plug-circle-check,\n \"street-view\": $fa-var-street-view,\n \"franc-sign\": $fa-var-franc-sign,\n \"volume-off\": $fa-var-volume-off,\n \"hands-asl-interpreting\": $fa-var-hands-asl-interpreting,\n \"american-sign-language-interpreting\": $fa-var-american-sign-language-interpreting,\n \"asl-interpreting\": $fa-var-asl-interpreting,\n \"hands-american-sign-language-interpreting\": $fa-var-hands-american-sign-language-interpreting,\n \"gear\": $fa-var-gear,\n \"cog\": $fa-var-cog,\n \"droplet-slash\": $fa-var-droplet-slash,\n \"tint-slash\": $fa-var-tint-slash,\n \"mosque\": $fa-var-mosque,\n \"mosquito\": $fa-var-mosquito,\n \"star-of-david\": $fa-var-star-of-david,\n \"person-military-rifle\": $fa-var-person-military-rifle,\n \"cart-shopping\": $fa-var-cart-shopping,\n \"shopping-cart\": $fa-var-shopping-cart,\n \"vials\": $fa-var-vials,\n \"plug-circle-plus\": $fa-var-plug-circle-plus,\n \"place-of-worship\": $fa-var-place-of-worship,\n \"grip-vertical\": $fa-var-grip-vertical,\n \"hexagon-nodes\": $fa-var-hexagon-nodes,\n \"arrow-turn-up\": $fa-var-arrow-turn-up,\n \"level-up\": $fa-var-level-up,\n \"u\": $fa-var-u,\n \"square-root-variable\": $fa-var-square-root-variable,\n \"square-root-alt\": $fa-var-square-root-alt,\n \"clock\": $fa-var-clock,\n \"clock-four\": $fa-var-clock-four,\n \"backward-step\": $fa-var-backward-step,\n \"step-backward\": $fa-var-step-backward,\n \"pallet\": $fa-var-pallet,\n \"faucet\": $fa-var-faucet,\n \"baseball-bat-ball\": $fa-var-baseball-bat-ball,\n \"s\": $fa-var-s,\n \"timeline\": $fa-var-timeline,\n \"keyboard\": $fa-var-keyboard,\n \"caret-down\": $fa-var-caret-down,\n \"house-chimney-medical\": $fa-var-house-chimney-medical,\n \"clinic-medical\": $fa-var-clinic-medical,\n \"temperature-three-quarters\": $fa-var-temperature-three-quarters,\n \"temperature-3\": $fa-var-temperature-3,\n \"thermometer-3\": $fa-var-thermometer-3,\n \"thermometer-three-quarters\": $fa-var-thermometer-three-quarters,\n \"mobile-screen\": $fa-var-mobile-screen,\n \"mobile-android-alt\": $fa-var-mobile-android-alt,\n \"plane-up\": $fa-var-plane-up,\n \"piggy-bank\": $fa-var-piggy-bank,\n \"battery-half\": $fa-var-battery-half,\n \"battery-3\": $fa-var-battery-3,\n \"mountain-city\": $fa-var-mountain-city,\n \"coins\": $fa-var-coins,\n \"khanda\": $fa-var-khanda,\n \"sliders\": $fa-var-sliders,\n \"sliders-h\": $fa-var-sliders-h,\n \"folder-tree\": $fa-var-folder-tree,\n \"network-wired\": $fa-var-network-wired,\n \"map-pin\": $fa-var-map-pin,\n \"hamsa\": $fa-var-hamsa,\n \"cent-sign\": $fa-var-cent-sign,\n \"flask\": $fa-var-flask,\n \"person-pregnant\": $fa-var-person-pregnant,\n \"wand-sparkles\": $fa-var-wand-sparkles,\n \"ellipsis-vertical\": $fa-var-ellipsis-vertical,\n \"ellipsis-v\": $fa-var-ellipsis-v,\n \"ticket\": $fa-var-ticket,\n \"power-off\": $fa-var-power-off,\n \"right-long\": $fa-var-right-long,\n \"long-arrow-alt-right\": $fa-var-long-arrow-alt-right,\n \"flag-usa\": $fa-var-flag-usa,\n \"laptop-file\": $fa-var-laptop-file,\n \"tty\": $fa-var-tty,\n \"teletype\": $fa-var-teletype,\n \"diagram-next\": $fa-var-diagram-next,\n \"person-rifle\": $fa-var-person-rifle,\n \"house-medical-circle-exclamation\": $fa-var-house-medical-circle-exclamation,\n \"closed-captioning\": $fa-var-closed-captioning,\n \"person-hiking\": $fa-var-person-hiking,\n \"hiking\": $fa-var-hiking,\n \"venus-double\": $fa-var-venus-double,\n \"images\": $fa-var-images,\n \"calculator\": $fa-var-calculator,\n \"people-pulling\": $fa-var-people-pulling,\n \"n\": $fa-var-n,\n \"cable-car\": $fa-var-cable-car,\n \"tram\": $fa-var-tram,\n \"cloud-rain\": $fa-var-cloud-rain,\n \"building-circle-xmark\": $fa-var-building-circle-xmark,\n \"ship\": $fa-var-ship,\n \"arrows-down-to-line\": $fa-var-arrows-down-to-line,\n \"download\": $fa-var-download,\n \"face-grin\": $fa-var-face-grin,\n \"grin\": $fa-var-grin,\n \"delete-left\": $fa-var-delete-left,\n \"backspace\": $fa-var-backspace,\n \"eye-dropper\": $fa-var-eye-dropper,\n \"eye-dropper-empty\": $fa-var-eye-dropper-empty,\n \"eyedropper\": $fa-var-eyedropper,\n \"file-circle-check\": $fa-var-file-circle-check,\n \"forward\": $fa-var-forward,\n \"mobile\": $fa-var-mobile,\n \"mobile-android\": $fa-var-mobile-android,\n \"mobile-phone\": $fa-var-mobile-phone,\n \"face-meh\": $fa-var-face-meh,\n \"meh\": $fa-var-meh,\n \"align-center\": $fa-var-align-center,\n \"book-skull\": $fa-var-book-skull,\n \"book-dead\": $fa-var-book-dead,\n \"id-card\": $fa-var-id-card,\n \"drivers-license\": $fa-var-drivers-license,\n \"outdent\": $fa-var-outdent,\n \"dedent\": $fa-var-dedent,\n \"heart-circle-exclamation\": $fa-var-heart-circle-exclamation,\n \"house\": $fa-var-house,\n \"home\": $fa-var-home,\n \"home-alt\": $fa-var-home-alt,\n \"home-lg-alt\": $fa-var-home-lg-alt,\n \"calendar-week\": $fa-var-calendar-week,\n \"laptop-medical\": $fa-var-laptop-medical,\n \"b\": $fa-var-b,\n \"file-medical\": $fa-var-file-medical,\n \"dice-one\": $fa-var-dice-one,\n \"kiwi-bird\": $fa-var-kiwi-bird,\n \"arrow-right-arrow-left\": $fa-var-arrow-right-arrow-left,\n \"exchange\": $fa-var-exchange,\n \"rotate-right\": $fa-var-rotate-right,\n \"redo-alt\": $fa-var-redo-alt,\n \"rotate-forward\": $fa-var-rotate-forward,\n \"utensils\": $fa-var-utensils,\n \"cutlery\": $fa-var-cutlery,\n \"arrow-up-wide-short\": $fa-var-arrow-up-wide-short,\n \"sort-amount-up\": $fa-var-sort-amount-up,\n \"mill-sign\": $fa-var-mill-sign,\n \"bowl-rice\": $fa-var-bowl-rice,\n \"skull\": $fa-var-skull,\n \"tower-broadcast\": $fa-var-tower-broadcast,\n \"broadcast-tower\": $fa-var-broadcast-tower,\n \"truck-pickup\": $fa-var-truck-pickup,\n \"up-long\": $fa-var-up-long,\n \"long-arrow-alt-up\": $fa-var-long-arrow-alt-up,\n \"stop\": $fa-var-stop,\n \"code-merge\": $fa-var-code-merge,\n \"upload\": $fa-var-upload,\n \"hurricane\": $fa-var-hurricane,\n \"mound\": $fa-var-mound,\n \"toilet-portable\": $fa-var-toilet-portable,\n \"compact-disc\": $fa-var-compact-disc,\n \"file-arrow-down\": $fa-var-file-arrow-down,\n \"file-download\": $fa-var-file-download,\n \"caravan\": $fa-var-caravan,\n \"shield-cat\": $fa-var-shield-cat,\n \"bolt\": $fa-var-bolt,\n \"zap\": $fa-var-zap,\n \"glass-water\": $fa-var-glass-water,\n \"oil-well\": $fa-var-oil-well,\n \"vault\": $fa-var-vault,\n \"mars\": $fa-var-mars,\n \"toilet\": $fa-var-toilet,\n \"plane-circle-xmark\": $fa-var-plane-circle-xmark,\n \"yen-sign\": $fa-var-yen-sign,\n \"cny\": $fa-var-cny,\n \"jpy\": $fa-var-jpy,\n \"rmb\": $fa-var-rmb,\n \"yen\": $fa-var-yen,\n \"ruble-sign\": $fa-var-ruble-sign,\n \"rouble\": $fa-var-rouble,\n \"rub\": $fa-var-rub,\n \"ruble\": $fa-var-ruble,\n \"sun\": $fa-var-sun,\n \"guitar\": $fa-var-guitar,\n \"face-laugh-wink\": $fa-var-face-laugh-wink,\n \"laugh-wink\": $fa-var-laugh-wink,\n \"horse-head\": $fa-var-horse-head,\n \"bore-hole\": $fa-var-bore-hole,\n \"industry\": $fa-var-industry,\n \"circle-down\": $fa-var-circle-down,\n \"arrow-alt-circle-down\": $fa-var-arrow-alt-circle-down,\n \"arrows-turn-to-dots\": $fa-var-arrows-turn-to-dots,\n \"florin-sign\": $fa-var-florin-sign,\n \"arrow-down-short-wide\": $fa-var-arrow-down-short-wide,\n \"sort-amount-desc\": $fa-var-sort-amount-desc,\n \"sort-amount-down-alt\": $fa-var-sort-amount-down-alt,\n \"less-than\": $fa-var-less-than,\n \"angle-down\": $fa-var-angle-down,\n \"car-tunnel\": $fa-var-car-tunnel,\n \"head-side-cough\": $fa-var-head-side-cough,\n \"grip-lines\": $fa-var-grip-lines,\n \"thumbs-down\": $fa-var-thumbs-down,\n \"user-lock\": $fa-var-user-lock,\n \"arrow-right-long\": $fa-var-arrow-right-long,\n \"long-arrow-right\": $fa-var-long-arrow-right,\n \"anchor-circle-xmark\": $fa-var-anchor-circle-xmark,\n \"ellipsis\": $fa-var-ellipsis,\n \"ellipsis-h\": $fa-var-ellipsis-h,\n \"chess-pawn\": $fa-var-chess-pawn,\n \"kit-medical\": $fa-var-kit-medical,\n \"first-aid\": $fa-var-first-aid,\n \"person-through-window\": $fa-var-person-through-window,\n \"toolbox\": $fa-var-toolbox,\n \"hands-holding-circle\": $fa-var-hands-holding-circle,\n \"bug\": $fa-var-bug,\n \"credit-card\": $fa-var-credit-card,\n \"credit-card-alt\": $fa-var-credit-card-alt,\n \"car\": $fa-var-car,\n \"automobile\": $fa-var-automobile,\n \"hand-holding-hand\": $fa-var-hand-holding-hand,\n \"book-open-reader\": $fa-var-book-open-reader,\n \"book-reader\": $fa-var-book-reader,\n \"mountain-sun\": $fa-var-mountain-sun,\n \"arrows-left-right-to-line\": $fa-var-arrows-left-right-to-line,\n \"dice-d20\": $fa-var-dice-d20,\n \"truck-droplet\": $fa-var-truck-droplet,\n \"file-circle-xmark\": $fa-var-file-circle-xmark,\n \"temperature-arrow-up\": $fa-var-temperature-arrow-up,\n \"temperature-up\": $fa-var-temperature-up,\n \"medal\": $fa-var-medal,\n \"bed\": $fa-var-bed,\n \"square-h\": $fa-var-square-h,\n \"h-square\": $fa-var-h-square,\n \"podcast\": $fa-var-podcast,\n \"temperature-full\": $fa-var-temperature-full,\n \"temperature-4\": $fa-var-temperature-4,\n \"thermometer-4\": $fa-var-thermometer-4,\n \"thermometer-full\": $fa-var-thermometer-full,\n \"bell\": $fa-var-bell,\n \"superscript\": $fa-var-superscript,\n \"plug-circle-xmark\": $fa-var-plug-circle-xmark,\n \"star-of-life\": $fa-var-star-of-life,\n \"phone-slash\": $fa-var-phone-slash,\n \"paint-roller\": $fa-var-paint-roller,\n \"handshake-angle\": $fa-var-handshake-angle,\n \"hands-helping\": $fa-var-hands-helping,\n \"location-dot\": $fa-var-location-dot,\n \"map-marker-alt\": $fa-var-map-marker-alt,\n \"file\": $fa-var-file,\n \"greater-than\": $fa-var-greater-than,\n \"person-swimming\": $fa-var-person-swimming,\n \"swimmer\": $fa-var-swimmer,\n \"arrow-down\": $fa-var-arrow-down,\n \"droplet\": $fa-var-droplet,\n \"tint\": $fa-var-tint,\n \"eraser\": $fa-var-eraser,\n \"earth-americas\": $fa-var-earth-americas,\n \"earth\": $fa-var-earth,\n \"earth-america\": $fa-var-earth-america,\n \"globe-americas\": $fa-var-globe-americas,\n \"person-burst\": $fa-var-person-burst,\n \"dove\": $fa-var-dove,\n \"battery-empty\": $fa-var-battery-empty,\n \"battery-0\": $fa-var-battery-0,\n \"socks\": $fa-var-socks,\n \"inbox\": $fa-var-inbox,\n \"section\": $fa-var-section,\n \"gauge-high\": $fa-var-gauge-high,\n \"tachometer-alt\": $fa-var-tachometer-alt,\n \"tachometer-alt-fast\": $fa-var-tachometer-alt-fast,\n \"envelope-open-text\": $fa-var-envelope-open-text,\n \"hospital\": $fa-var-hospital,\n \"hospital-alt\": $fa-var-hospital-alt,\n \"hospital-wide\": $fa-var-hospital-wide,\n \"wine-bottle\": $fa-var-wine-bottle,\n \"chess-rook\": $fa-var-chess-rook,\n \"bars-staggered\": $fa-var-bars-staggered,\n \"reorder\": $fa-var-reorder,\n \"stream\": $fa-var-stream,\n \"dharmachakra\": $fa-var-dharmachakra,\n \"hotdog\": $fa-var-hotdog,\n \"person-walking-with-cane\": $fa-var-person-walking-with-cane,\n \"blind\": $fa-var-blind,\n \"drum\": $fa-var-drum,\n \"ice-cream\": $fa-var-ice-cream,\n \"heart-circle-bolt\": $fa-var-heart-circle-bolt,\n \"fax\": $fa-var-fax,\n \"paragraph\": $fa-var-paragraph,\n \"check-to-slot\": $fa-var-check-to-slot,\n \"vote-yea\": $fa-var-vote-yea,\n \"star-half\": $fa-var-star-half,\n \"boxes-stacked\": $fa-var-boxes-stacked,\n \"boxes\": $fa-var-boxes,\n \"boxes-alt\": $fa-var-boxes-alt,\n \"link\": $fa-var-link,\n \"chain\": $fa-var-chain,\n \"ear-listen\": $fa-var-ear-listen,\n \"assistive-listening-systems\": $fa-var-assistive-listening-systems,\n \"tree-city\": $fa-var-tree-city,\n \"play\": $fa-var-play,\n \"font\": $fa-var-font,\n \"table-cells-row-lock\": $fa-var-table-cells-row-lock,\n \"rupiah-sign\": $fa-var-rupiah-sign,\n \"magnifying-glass\": $fa-var-magnifying-glass,\n \"search\": $fa-var-search,\n \"table-tennis-paddle-ball\": $fa-var-table-tennis-paddle-ball,\n \"ping-pong-paddle-ball\": $fa-var-ping-pong-paddle-ball,\n \"table-tennis\": $fa-var-table-tennis,\n \"person-dots-from-line\": $fa-var-person-dots-from-line,\n \"diagnoses\": $fa-var-diagnoses,\n \"trash-can-arrow-up\": $fa-var-trash-can-arrow-up,\n \"trash-restore-alt\": $fa-var-trash-restore-alt,\n \"naira-sign\": $fa-var-naira-sign,\n \"cart-arrow-down\": $fa-var-cart-arrow-down,\n \"walkie-talkie\": $fa-var-walkie-talkie,\n \"file-pen\": $fa-var-file-pen,\n \"file-edit\": $fa-var-file-edit,\n \"receipt\": $fa-var-receipt,\n \"square-pen\": $fa-var-square-pen,\n \"pen-square\": $fa-var-pen-square,\n \"pencil-square\": $fa-var-pencil-square,\n \"suitcase-rolling\": $fa-var-suitcase-rolling,\n \"person-circle-exclamation\": $fa-var-person-circle-exclamation,\n \"chevron-down\": $fa-var-chevron-down,\n \"battery-full\": $fa-var-battery-full,\n \"battery\": $fa-var-battery,\n \"battery-5\": $fa-var-battery-5,\n \"skull-crossbones\": $fa-var-skull-crossbones,\n \"code-compare\": $fa-var-code-compare,\n \"list-ul\": $fa-var-list-ul,\n \"list-dots\": $fa-var-list-dots,\n \"school-lock\": $fa-var-school-lock,\n \"tower-cell\": $fa-var-tower-cell,\n \"down-long\": $fa-var-down-long,\n \"long-arrow-alt-down\": $fa-var-long-arrow-alt-down,\n \"ranking-star\": $fa-var-ranking-star,\n \"chess-king\": $fa-var-chess-king,\n \"person-harassing\": $fa-var-person-harassing,\n \"brazilian-real-sign\": $fa-var-brazilian-real-sign,\n \"landmark-dome\": $fa-var-landmark-dome,\n \"landmark-alt\": $fa-var-landmark-alt,\n \"arrow-up\": $fa-var-arrow-up,\n \"tv\": $fa-var-tv,\n \"television\": $fa-var-television,\n \"tv-alt\": $fa-var-tv-alt,\n \"shrimp\": $fa-var-shrimp,\n \"list-check\": $fa-var-list-check,\n \"tasks\": $fa-var-tasks,\n \"jug-detergent\": $fa-var-jug-detergent,\n \"circle-user\": $fa-var-circle-user,\n \"user-circle\": $fa-var-user-circle,\n \"user-shield\": $fa-var-user-shield,\n \"wind\": $fa-var-wind,\n \"car-burst\": $fa-var-car-burst,\n \"car-crash\": $fa-var-car-crash,\n \"y\": $fa-var-y,\n \"person-snowboarding\": $fa-var-person-snowboarding,\n \"snowboarding\": $fa-var-snowboarding,\n \"truck-fast\": $fa-var-truck-fast,\n \"shipping-fast\": $fa-var-shipping-fast,\n \"fish\": $fa-var-fish,\n \"user-graduate\": $fa-var-user-graduate,\n \"circle-half-stroke\": $fa-var-circle-half-stroke,\n \"adjust\": $fa-var-adjust,\n \"clapperboard\": $fa-var-clapperboard,\n \"circle-radiation\": $fa-var-circle-radiation,\n \"radiation-alt\": $fa-var-radiation-alt,\n \"baseball\": $fa-var-baseball,\n \"baseball-ball\": $fa-var-baseball-ball,\n \"jet-fighter-up\": $fa-var-jet-fighter-up,\n \"diagram-project\": $fa-var-diagram-project,\n \"project-diagram\": $fa-var-project-diagram,\n \"copy\": $fa-var-copy,\n \"volume-xmark\": $fa-var-volume-xmark,\n \"volume-mute\": $fa-var-volume-mute,\n \"volume-times\": $fa-var-volume-times,\n \"hand-sparkles\": $fa-var-hand-sparkles,\n \"grip\": $fa-var-grip,\n \"grip-horizontal\": $fa-var-grip-horizontal,\n \"share-from-square\": $fa-var-share-from-square,\n \"share-square\": $fa-var-share-square,\n \"child-combatant\": $fa-var-child-combatant,\n \"child-rifle\": $fa-var-child-rifle,\n \"gun\": $fa-var-gun,\n \"square-phone\": $fa-var-square-phone,\n \"phone-square\": $fa-var-phone-square,\n \"plus\": $fa-var-plus,\n \"add\": $fa-var-add,\n \"expand\": $fa-var-expand,\n \"computer\": $fa-var-computer,\n \"xmark\": $fa-var-xmark,\n \"close\": $fa-var-close,\n \"multiply\": $fa-var-multiply,\n \"remove\": $fa-var-remove,\n \"times\": $fa-var-times,\n \"arrows-up-down-left-right\": $fa-var-arrows-up-down-left-right,\n \"arrows\": $fa-var-arrows,\n \"chalkboard-user\": $fa-var-chalkboard-user,\n \"chalkboard-teacher\": $fa-var-chalkboard-teacher,\n \"peso-sign\": $fa-var-peso-sign,\n \"building-shield\": $fa-var-building-shield,\n \"baby\": $fa-var-baby,\n \"users-line\": $fa-var-users-line,\n \"quote-left\": $fa-var-quote-left,\n \"quote-left-alt\": $fa-var-quote-left-alt,\n \"tractor\": $fa-var-tractor,\n \"trash-arrow-up\": $fa-var-trash-arrow-up,\n \"trash-restore\": $fa-var-trash-restore,\n \"arrow-down-up-lock\": $fa-var-arrow-down-up-lock,\n \"lines-leaning\": $fa-var-lines-leaning,\n \"ruler-combined\": $fa-var-ruler-combined,\n \"copyright\": $fa-var-copyright,\n \"equals\": $fa-var-equals,\n \"blender\": $fa-var-blender,\n \"teeth\": $fa-var-teeth,\n \"shekel-sign\": $fa-var-shekel-sign,\n \"ils\": $fa-var-ils,\n \"shekel\": $fa-var-shekel,\n \"sheqel\": $fa-var-sheqel,\n \"sheqel-sign\": $fa-var-sheqel-sign,\n \"map\": $fa-var-map,\n \"rocket\": $fa-var-rocket,\n \"photo-film\": $fa-var-photo-film,\n \"photo-video\": $fa-var-photo-video,\n \"folder-minus\": $fa-var-folder-minus,\n \"hexagon-nodes-bolt\": $fa-var-hexagon-nodes-bolt,\n \"store\": $fa-var-store,\n \"arrow-trend-up\": $fa-var-arrow-trend-up,\n \"plug-circle-minus\": $fa-var-plug-circle-minus,\n \"sign-hanging\": $fa-var-sign-hanging,\n \"sign\": $fa-var-sign,\n \"bezier-curve\": $fa-var-bezier-curve,\n \"bell-slash\": $fa-var-bell-slash,\n \"tablet\": $fa-var-tablet,\n \"tablet-android\": $fa-var-tablet-android,\n \"school-flag\": $fa-var-school-flag,\n \"fill\": $fa-var-fill,\n \"angle-up\": $fa-var-angle-up,\n \"drumstick-bite\": $fa-var-drumstick-bite,\n \"holly-berry\": $fa-var-holly-berry,\n \"chevron-left\": $fa-var-chevron-left,\n \"bacteria\": $fa-var-bacteria,\n \"hand-lizard\": $fa-var-hand-lizard,\n \"notdef\": $fa-var-notdef,\n \"disease\": $fa-var-disease,\n \"briefcase-medical\": $fa-var-briefcase-medical,\n \"genderless\": $fa-var-genderless,\n \"chevron-right\": $fa-var-chevron-right,\n \"retweet\": $fa-var-retweet,\n \"car-rear\": $fa-var-car-rear,\n \"car-alt\": $fa-var-car-alt,\n \"pump-soap\": $fa-var-pump-soap,\n \"video-slash\": $fa-var-video-slash,\n \"battery-quarter\": $fa-var-battery-quarter,\n \"battery-2\": $fa-var-battery-2,\n \"radio\": $fa-var-radio,\n \"baby-carriage\": $fa-var-baby-carriage,\n \"carriage-baby\": $fa-var-carriage-baby,\n \"traffic-light\": $fa-var-traffic-light,\n \"thermometer\": $fa-var-thermometer,\n \"vr-cardboard\": $fa-var-vr-cardboard,\n \"hand-middle-finger\": $fa-var-hand-middle-finger,\n \"percent\": $fa-var-percent,\n \"percentage\": $fa-var-percentage,\n \"truck-moving\": $fa-var-truck-moving,\n \"glass-water-droplet\": $fa-var-glass-water-droplet,\n \"display\": $fa-var-display,\n \"face-smile\": $fa-var-face-smile,\n \"smile\": $fa-var-smile,\n \"thumbtack\": $fa-var-thumbtack,\n \"thumb-tack\": $fa-var-thumb-tack,\n \"trophy\": $fa-var-trophy,\n \"person-praying\": $fa-var-person-praying,\n \"pray\": $fa-var-pray,\n \"hammer\": $fa-var-hammer,\n \"hand-peace\": $fa-var-hand-peace,\n \"rotate\": $fa-var-rotate,\n \"sync-alt\": $fa-var-sync-alt,\n \"spinner\": $fa-var-spinner,\n \"robot\": $fa-var-robot,\n \"peace\": $fa-var-peace,\n \"gears\": $fa-var-gears,\n \"cogs\": $fa-var-cogs,\n \"warehouse\": $fa-var-warehouse,\n \"arrow-up-right-dots\": $fa-var-arrow-up-right-dots,\n \"splotch\": $fa-var-splotch,\n \"face-grin-hearts\": $fa-var-face-grin-hearts,\n \"grin-hearts\": $fa-var-grin-hearts,\n \"dice-four\": $fa-var-dice-four,\n \"sim-card\": $fa-var-sim-card,\n \"transgender\": $fa-var-transgender,\n \"transgender-alt\": $fa-var-transgender-alt,\n \"mercury\": $fa-var-mercury,\n \"arrow-turn-down\": $fa-var-arrow-turn-down,\n \"level-down\": $fa-var-level-down,\n \"person-falling-burst\": $fa-var-person-falling-burst,\n \"award\": $fa-var-award,\n \"ticket-simple\": $fa-var-ticket-simple,\n \"ticket-alt\": $fa-var-ticket-alt,\n \"building\": $fa-var-building,\n \"angles-left\": $fa-var-angles-left,\n \"angle-double-left\": $fa-var-angle-double-left,\n \"qrcode\": $fa-var-qrcode,\n \"clock-rotate-left\": $fa-var-clock-rotate-left,\n \"history\": $fa-var-history,\n \"face-grin-beam-sweat\": $fa-var-face-grin-beam-sweat,\n \"grin-beam-sweat\": $fa-var-grin-beam-sweat,\n \"file-export\": $fa-var-file-export,\n \"arrow-right-from-file\": $fa-var-arrow-right-from-file,\n \"shield\": $fa-var-shield,\n \"shield-blank\": $fa-var-shield-blank,\n \"arrow-up-short-wide\": $fa-var-arrow-up-short-wide,\n \"sort-amount-up-alt\": $fa-var-sort-amount-up-alt,\n \"comment-nodes\": $fa-var-comment-nodes,\n \"house-medical\": $fa-var-house-medical,\n \"golf-ball-tee\": $fa-var-golf-ball-tee,\n \"golf-ball\": $fa-var-golf-ball,\n \"circle-chevron-left\": $fa-var-circle-chevron-left,\n \"chevron-circle-left\": $fa-var-chevron-circle-left,\n \"house-chimney-window\": $fa-var-house-chimney-window,\n \"pen-nib\": $fa-var-pen-nib,\n \"tent-arrow-turn-left\": $fa-var-tent-arrow-turn-left,\n \"tents\": $fa-var-tents,\n \"wand-magic\": $fa-var-wand-magic,\n \"magic\": $fa-var-magic,\n \"dog\": $fa-var-dog,\n \"carrot\": $fa-var-carrot,\n \"moon\": $fa-var-moon,\n \"wine-glass-empty\": $fa-var-wine-glass-empty,\n \"wine-glass-alt\": $fa-var-wine-glass-alt,\n \"cheese\": $fa-var-cheese,\n \"yin-yang\": $fa-var-yin-yang,\n \"music\": $fa-var-music,\n \"code-commit\": $fa-var-code-commit,\n \"temperature-low\": $fa-var-temperature-low,\n \"person-biking\": $fa-var-person-biking,\n \"biking\": $fa-var-biking,\n \"broom\": $fa-var-broom,\n \"shield-heart\": $fa-var-shield-heart,\n \"gopuram\": $fa-var-gopuram,\n \"earth-oceania\": $fa-var-earth-oceania,\n \"globe-oceania\": $fa-var-globe-oceania,\n \"square-xmark\": $fa-var-square-xmark,\n \"times-square\": $fa-var-times-square,\n \"xmark-square\": $fa-var-xmark-square,\n \"hashtag\": $fa-var-hashtag,\n \"up-right-and-down-left-from-center\": $fa-var-up-right-and-down-left-from-center,\n \"expand-alt\": $fa-var-expand-alt,\n \"oil-can\": $fa-var-oil-can,\n \"t\": $fa-var-t,\n \"hippo\": $fa-var-hippo,\n \"chart-column\": $fa-var-chart-column,\n \"infinity\": $fa-var-infinity,\n \"vial-circle-check\": $fa-var-vial-circle-check,\n \"person-arrow-down-to-line\": $fa-var-person-arrow-down-to-line,\n \"voicemail\": $fa-var-voicemail,\n \"fan\": $fa-var-fan,\n \"person-walking-luggage\": $fa-var-person-walking-luggage,\n \"up-down\": $fa-var-up-down,\n \"arrows-alt-v\": $fa-var-arrows-alt-v,\n \"cloud-moon-rain\": $fa-var-cloud-moon-rain,\n \"calendar\": $fa-var-calendar,\n \"trailer\": $fa-var-trailer,\n \"bahai\": $fa-var-bahai,\n \"haykal\": $fa-var-haykal,\n \"sd-card\": $fa-var-sd-card,\n \"dragon\": $fa-var-dragon,\n \"shoe-prints\": $fa-var-shoe-prints,\n \"circle-plus\": $fa-var-circle-plus,\n \"plus-circle\": $fa-var-plus-circle,\n \"face-grin-tongue-wink\": $fa-var-face-grin-tongue-wink,\n \"grin-tongue-wink\": $fa-var-grin-tongue-wink,\n \"hand-holding\": $fa-var-hand-holding,\n \"plug-circle-exclamation\": $fa-var-plug-circle-exclamation,\n \"link-slash\": $fa-var-link-slash,\n \"chain-broken\": $fa-var-chain-broken,\n \"chain-slash\": $fa-var-chain-slash,\n \"unlink\": $fa-var-unlink,\n \"clone\": $fa-var-clone,\n \"person-walking-arrow-loop-left\": $fa-var-person-walking-arrow-loop-left,\n \"arrow-up-z-a\": $fa-var-arrow-up-z-a,\n \"sort-alpha-up-alt\": $fa-var-sort-alpha-up-alt,\n \"fire-flame-curved\": $fa-var-fire-flame-curved,\n \"fire-alt\": $fa-var-fire-alt,\n \"tornado\": $fa-var-tornado,\n \"file-circle-plus\": $fa-var-file-circle-plus,\n \"book-quran\": $fa-var-book-quran,\n \"quran\": $fa-var-quran,\n \"anchor\": $fa-var-anchor,\n \"border-all\": $fa-var-border-all,\n \"face-angry\": $fa-var-face-angry,\n \"angry\": $fa-var-angry,\n \"cookie-bite\": $fa-var-cookie-bite,\n \"arrow-trend-down\": $fa-var-arrow-trend-down,\n \"rss\": $fa-var-rss,\n \"feed\": $fa-var-feed,\n \"draw-polygon\": $fa-var-draw-polygon,\n \"scale-balanced\": $fa-var-scale-balanced,\n \"balance-scale\": $fa-var-balance-scale,\n \"gauge-simple-high\": $fa-var-gauge-simple-high,\n \"tachometer\": $fa-var-tachometer,\n \"tachometer-fast\": $fa-var-tachometer-fast,\n \"shower\": $fa-var-shower,\n \"desktop\": $fa-var-desktop,\n \"desktop-alt\": $fa-var-desktop-alt,\n \"m\": $fa-var-m,\n \"table-list\": $fa-var-table-list,\n \"th-list\": $fa-var-th-list,\n \"comment-sms\": $fa-var-comment-sms,\n \"sms\": $fa-var-sms,\n \"book\": $fa-var-book,\n \"user-plus\": $fa-var-user-plus,\n \"check\": $fa-var-check,\n \"battery-three-quarters\": $fa-var-battery-three-quarters,\n \"battery-4\": $fa-var-battery-4,\n \"house-circle-check\": $fa-var-house-circle-check,\n \"angle-left\": $fa-var-angle-left,\n \"diagram-successor\": $fa-var-diagram-successor,\n \"truck-arrow-right\": $fa-var-truck-arrow-right,\n \"arrows-split-up-and-left\": $fa-var-arrows-split-up-and-left,\n \"hand-fist\": $fa-var-hand-fist,\n \"fist-raised\": $fa-var-fist-raised,\n \"cloud-moon\": $fa-var-cloud-moon,\n \"briefcase\": $fa-var-briefcase,\n \"person-falling\": $fa-var-person-falling,\n \"image-portrait\": $fa-var-image-portrait,\n \"portrait\": $fa-var-portrait,\n \"user-tag\": $fa-var-user-tag,\n \"rug\": $fa-var-rug,\n \"earth-europe\": $fa-var-earth-europe,\n \"globe-europe\": $fa-var-globe-europe,\n \"cart-flatbed-suitcase\": $fa-var-cart-flatbed-suitcase,\n \"luggage-cart\": $fa-var-luggage-cart,\n \"rectangle-xmark\": $fa-var-rectangle-xmark,\n \"rectangle-times\": $fa-var-rectangle-times,\n \"times-rectangle\": $fa-var-times-rectangle,\n \"window-close\": $fa-var-window-close,\n \"baht-sign\": $fa-var-baht-sign,\n \"book-open\": $fa-var-book-open,\n \"book-journal-whills\": $fa-var-book-journal-whills,\n \"journal-whills\": $fa-var-journal-whills,\n \"handcuffs\": $fa-var-handcuffs,\n \"triangle-exclamation\": $fa-var-triangle-exclamation,\n \"exclamation-triangle\": $fa-var-exclamation-triangle,\n \"warning\": $fa-var-warning,\n \"database\": $fa-var-database,\n \"share\": $fa-var-share,\n \"mail-forward\": $fa-var-mail-forward,\n \"bottle-droplet\": $fa-var-bottle-droplet,\n \"mask-face\": $fa-var-mask-face,\n \"hill-rockslide\": $fa-var-hill-rockslide,\n \"right-left\": $fa-var-right-left,\n \"exchange-alt\": $fa-var-exchange-alt,\n \"paper-plane\": $fa-var-paper-plane,\n \"road-circle-exclamation\": $fa-var-road-circle-exclamation,\n \"dungeon\": $fa-var-dungeon,\n \"align-right\": $fa-var-align-right,\n \"money-bill-1-wave\": $fa-var-money-bill-1-wave,\n \"money-bill-wave-alt\": $fa-var-money-bill-wave-alt,\n \"life-ring\": $fa-var-life-ring,\n \"hands\": $fa-var-hands,\n \"sign-language\": $fa-var-sign-language,\n \"signing\": $fa-var-signing,\n \"calendar-day\": $fa-var-calendar-day,\n \"water-ladder\": $fa-var-water-ladder,\n \"ladder-water\": $fa-var-ladder-water,\n \"swimming-pool\": $fa-var-swimming-pool,\n \"arrows-up-down\": $fa-var-arrows-up-down,\n \"arrows-v\": $fa-var-arrows-v,\n \"face-grimace\": $fa-var-face-grimace,\n \"grimace\": $fa-var-grimace,\n \"wheelchair-move\": $fa-var-wheelchair-move,\n \"wheelchair-alt\": $fa-var-wheelchair-alt,\n \"turn-down\": $fa-var-turn-down,\n \"level-down-alt\": $fa-var-level-down-alt,\n \"person-walking-arrow-right\": $fa-var-person-walking-arrow-right,\n \"square-envelope\": $fa-var-square-envelope,\n \"envelope-square\": $fa-var-envelope-square,\n \"dice\": $fa-var-dice,\n \"bowling-ball\": $fa-var-bowling-ball,\n \"brain\": $fa-var-brain,\n \"bandage\": $fa-var-bandage,\n \"band-aid\": $fa-var-band-aid,\n \"calendar-minus\": $fa-var-calendar-minus,\n \"circle-xmark\": $fa-var-circle-xmark,\n \"times-circle\": $fa-var-times-circle,\n \"xmark-circle\": $fa-var-xmark-circle,\n \"gifts\": $fa-var-gifts,\n \"hotel\": $fa-var-hotel,\n \"earth-asia\": $fa-var-earth-asia,\n \"globe-asia\": $fa-var-globe-asia,\n \"id-card-clip\": $fa-var-id-card-clip,\n \"id-card-alt\": $fa-var-id-card-alt,\n \"magnifying-glass-plus\": $fa-var-magnifying-glass-plus,\n \"search-plus\": $fa-var-search-plus,\n \"thumbs-up\": $fa-var-thumbs-up,\n \"user-clock\": $fa-var-user-clock,\n \"hand-dots\": $fa-var-hand-dots,\n \"allergies\": $fa-var-allergies,\n \"file-invoice\": $fa-var-file-invoice,\n \"window-minimize\": $fa-var-window-minimize,\n \"mug-saucer\": $fa-var-mug-saucer,\n \"coffee\": $fa-var-coffee,\n \"brush\": $fa-var-brush,\n \"file-half-dashed\": $fa-var-file-half-dashed,\n \"mask\": $fa-var-mask,\n \"magnifying-glass-minus\": $fa-var-magnifying-glass-minus,\n \"search-minus\": $fa-var-search-minus,\n \"ruler-vertical\": $fa-var-ruler-vertical,\n \"user-large\": $fa-var-user-large,\n \"user-alt\": $fa-var-user-alt,\n \"train-tram\": $fa-var-train-tram,\n \"user-nurse\": $fa-var-user-nurse,\n \"syringe\": $fa-var-syringe,\n \"cloud-sun\": $fa-var-cloud-sun,\n \"stopwatch-20\": $fa-var-stopwatch-20,\n \"square-full\": $fa-var-square-full,\n \"magnet\": $fa-var-magnet,\n \"jar\": $fa-var-jar,\n \"note-sticky\": $fa-var-note-sticky,\n \"sticky-note\": $fa-var-sticky-note,\n \"bug-slash\": $fa-var-bug-slash,\n \"arrow-up-from-water-pump\": $fa-var-arrow-up-from-water-pump,\n \"bone\": $fa-var-bone,\n \"table-cells-row-unlock\": $fa-var-table-cells-row-unlock,\n \"user-injured\": $fa-var-user-injured,\n \"face-sad-tear\": $fa-var-face-sad-tear,\n \"sad-tear\": $fa-var-sad-tear,\n \"plane\": $fa-var-plane,\n \"tent-arrows-down\": $fa-var-tent-arrows-down,\n \"exclamation\": $fa-var-exclamation,\n \"arrows-spin\": $fa-var-arrows-spin,\n \"print\": $fa-var-print,\n \"turkish-lira-sign\": $fa-var-turkish-lira-sign,\n \"try\": $fa-var-try,\n \"turkish-lira\": $fa-var-turkish-lira,\n \"dollar-sign\": $fa-var-dollar-sign,\n \"dollar\": $fa-var-dollar,\n \"usd\": $fa-var-usd,\n \"x\": $fa-var-x,\n \"magnifying-glass-dollar\": $fa-var-magnifying-glass-dollar,\n \"search-dollar\": $fa-var-search-dollar,\n \"users-gear\": $fa-var-users-gear,\n \"users-cog\": $fa-var-users-cog,\n \"person-military-pointing\": $fa-var-person-military-pointing,\n \"building-columns\": $fa-var-building-columns,\n \"bank\": $fa-var-bank,\n \"institution\": $fa-var-institution,\n \"museum\": $fa-var-museum,\n \"university\": $fa-var-university,\n \"umbrella\": $fa-var-umbrella,\n \"trowel\": $fa-var-trowel,\n \"d\": $fa-var-d,\n \"stapler\": $fa-var-stapler,\n \"masks-theater\": $fa-var-masks-theater,\n \"theater-masks\": $fa-var-theater-masks,\n \"kip-sign\": $fa-var-kip-sign,\n \"hand-point-left\": $fa-var-hand-point-left,\n \"handshake-simple\": $fa-var-handshake-simple,\n \"handshake-alt\": $fa-var-handshake-alt,\n \"jet-fighter\": $fa-var-jet-fighter,\n \"fighter-jet\": $fa-var-fighter-jet,\n \"square-share-nodes\": $fa-var-square-share-nodes,\n \"share-alt-square\": $fa-var-share-alt-square,\n \"barcode\": $fa-var-barcode,\n \"plus-minus\": $fa-var-plus-minus,\n \"video\": $fa-var-video,\n \"video-camera\": $fa-var-video-camera,\n \"graduation-cap\": $fa-var-graduation-cap,\n \"mortar-board\": $fa-var-mortar-board,\n \"hand-holding-medical\": $fa-var-hand-holding-medical,\n \"person-circle-check\": $fa-var-person-circle-check,\n \"turn-up\": $fa-var-turn-up,\n \"level-up-alt\": $fa-var-level-up-alt,\n);\n\n$fa-brand-icons: (\n \"monero\": $fa-var-monero,\n \"hooli\": $fa-var-hooli,\n \"yelp\": $fa-var-yelp,\n \"cc-visa\": $fa-var-cc-visa,\n \"lastfm\": $fa-var-lastfm,\n \"shopware\": $fa-var-shopware,\n \"creative-commons-nc\": $fa-var-creative-commons-nc,\n \"aws\": $fa-var-aws,\n \"redhat\": $fa-var-redhat,\n \"yoast\": $fa-var-yoast,\n \"cloudflare\": $fa-var-cloudflare,\n \"ups\": $fa-var-ups,\n \"pixiv\": $fa-var-pixiv,\n \"wpexplorer\": $fa-var-wpexplorer,\n \"dyalog\": $fa-var-dyalog,\n \"bity\": $fa-var-bity,\n \"stackpath\": $fa-var-stackpath,\n \"buysellads\": $fa-var-buysellads,\n \"first-order\": $fa-var-first-order,\n \"modx\": $fa-var-modx,\n \"guilded\": $fa-var-guilded,\n \"vnv\": $fa-var-vnv,\n \"square-js\": $fa-var-square-js,\n \"js-square\": $fa-var-js-square,\n \"microsoft\": $fa-var-microsoft,\n \"qq\": $fa-var-qq,\n \"orcid\": $fa-var-orcid,\n \"java\": $fa-var-java,\n \"invision\": $fa-var-invision,\n \"creative-commons-pd-alt\": $fa-var-creative-commons-pd-alt,\n \"centercode\": $fa-var-centercode,\n \"glide-g\": $fa-var-glide-g,\n \"drupal\": $fa-var-drupal,\n \"jxl\": $fa-var-jxl,\n \"dart-lang\": $fa-var-dart-lang,\n \"hire-a-helper\": $fa-var-hire-a-helper,\n \"creative-commons-by\": $fa-var-creative-commons-by,\n \"unity\": $fa-var-unity,\n \"whmcs\": $fa-var-whmcs,\n \"rocketchat\": $fa-var-rocketchat,\n \"vk\": $fa-var-vk,\n \"untappd\": $fa-var-untappd,\n \"mailchimp\": $fa-var-mailchimp,\n \"css3-alt\": $fa-var-css3-alt,\n \"square-reddit\": $fa-var-square-reddit,\n \"reddit-square\": $fa-var-reddit-square,\n \"vimeo-v\": $fa-var-vimeo-v,\n \"contao\": $fa-var-contao,\n \"square-font-awesome\": $fa-var-square-font-awesome,\n \"deskpro\": $fa-var-deskpro,\n \"brave\": $fa-var-brave,\n \"sistrix\": $fa-var-sistrix,\n \"square-instagram\": $fa-var-square-instagram,\n \"instagram-square\": $fa-var-instagram-square,\n \"battle-net\": $fa-var-battle-net,\n \"the-red-yeti\": $fa-var-the-red-yeti,\n \"square-hacker-news\": $fa-var-square-hacker-news,\n \"hacker-news-square\": $fa-var-hacker-news-square,\n \"edge\": $fa-var-edge,\n \"threads\": $fa-var-threads,\n \"napster\": $fa-var-napster,\n \"square-snapchat\": $fa-var-square-snapchat,\n \"snapchat-square\": $fa-var-snapchat-square,\n \"google-plus-g\": $fa-var-google-plus-g,\n \"artstation\": $fa-var-artstation,\n \"markdown\": $fa-var-markdown,\n \"sourcetree\": $fa-var-sourcetree,\n \"google-plus\": $fa-var-google-plus,\n \"diaspora\": $fa-var-diaspora,\n \"foursquare\": $fa-var-foursquare,\n \"stack-overflow\": $fa-var-stack-overflow,\n \"github-alt\": $fa-var-github-alt,\n \"phoenix-squadron\": $fa-var-phoenix-squadron,\n \"pagelines\": $fa-var-pagelines,\n \"algolia\": $fa-var-algolia,\n \"red-river\": $fa-var-red-river,\n \"creative-commons-sa\": $fa-var-creative-commons-sa,\n \"safari\": $fa-var-safari,\n \"google\": $fa-var-google,\n \"square-font-awesome-stroke\": $fa-var-square-font-awesome-stroke,\n \"font-awesome-alt\": $fa-var-font-awesome-alt,\n \"atlassian\": $fa-var-atlassian,\n \"linkedin-in\": $fa-var-linkedin-in,\n \"digital-ocean\": $fa-var-digital-ocean,\n \"nimblr\": $fa-var-nimblr,\n \"chromecast\": $fa-var-chromecast,\n \"evernote\": $fa-var-evernote,\n \"hacker-news\": $fa-var-hacker-news,\n \"creative-commons-sampling\": $fa-var-creative-commons-sampling,\n \"adversal\": $fa-var-adversal,\n \"creative-commons\": $fa-var-creative-commons,\n \"watchman-monitoring\": $fa-var-watchman-monitoring,\n \"fonticons\": $fa-var-fonticons,\n \"weixin\": $fa-var-weixin,\n \"shirtsinbulk\": $fa-var-shirtsinbulk,\n \"codepen\": $fa-var-codepen,\n \"git-alt\": $fa-var-git-alt,\n \"lyft\": $fa-var-lyft,\n \"rev\": $fa-var-rev,\n \"windows\": $fa-var-windows,\n \"wizards-of-the-coast\": $fa-var-wizards-of-the-coast,\n \"square-viadeo\": $fa-var-square-viadeo,\n \"viadeo-square\": $fa-var-viadeo-square,\n \"meetup\": $fa-var-meetup,\n \"centos\": $fa-var-centos,\n \"adn\": $fa-var-adn,\n \"cloudsmith\": $fa-var-cloudsmith,\n \"opensuse\": $fa-var-opensuse,\n \"pied-piper-alt\": $fa-var-pied-piper-alt,\n \"square-dribbble\": $fa-var-square-dribbble,\n \"dribbble-square\": $fa-var-dribbble-square,\n \"codiepie\": $fa-var-codiepie,\n \"node\": $fa-var-node,\n \"mix\": $fa-var-mix,\n \"steam\": $fa-var-steam,\n \"cc-apple-pay\": $fa-var-cc-apple-pay,\n \"scribd\": $fa-var-scribd,\n \"debian\": $fa-var-debian,\n \"openid\": $fa-var-openid,\n \"instalod\": $fa-var-instalod,\n \"files-pinwheel\": $fa-var-files-pinwheel,\n \"expeditedssl\": $fa-var-expeditedssl,\n \"sellcast\": $fa-var-sellcast,\n \"square-twitter\": $fa-var-square-twitter,\n \"twitter-square\": $fa-var-twitter-square,\n \"r-project\": $fa-var-r-project,\n \"delicious\": $fa-var-delicious,\n \"freebsd\": $fa-var-freebsd,\n \"vuejs\": $fa-var-vuejs,\n \"accusoft\": $fa-var-accusoft,\n \"ioxhost\": $fa-var-ioxhost,\n \"fonticons-fi\": $fa-var-fonticons-fi,\n \"app-store\": $fa-var-app-store,\n \"cc-mastercard\": $fa-var-cc-mastercard,\n \"itunes-note\": $fa-var-itunes-note,\n \"golang\": $fa-var-golang,\n \"kickstarter\": $fa-var-kickstarter,\n \"square-kickstarter\": $fa-var-square-kickstarter,\n \"grav\": $fa-var-grav,\n \"weibo\": $fa-var-weibo,\n \"uncharted\": $fa-var-uncharted,\n \"firstdraft\": $fa-var-firstdraft,\n \"square-youtube\": $fa-var-square-youtube,\n \"youtube-square\": $fa-var-youtube-square,\n \"wikipedia-w\": $fa-var-wikipedia-w,\n \"wpressr\": $fa-var-wpressr,\n \"rendact\": $fa-var-rendact,\n \"angellist\": $fa-var-angellist,\n \"galactic-republic\": $fa-var-galactic-republic,\n \"nfc-directional\": $fa-var-nfc-directional,\n \"skype\": $fa-var-skype,\n \"joget\": $fa-var-joget,\n \"fedora\": $fa-var-fedora,\n \"stripe-s\": $fa-var-stripe-s,\n \"meta\": $fa-var-meta,\n \"laravel\": $fa-var-laravel,\n \"hotjar\": $fa-var-hotjar,\n \"bluetooth-b\": $fa-var-bluetooth-b,\n \"square-letterboxd\": $fa-var-square-letterboxd,\n \"sticker-mule\": $fa-var-sticker-mule,\n \"creative-commons-zero\": $fa-var-creative-commons-zero,\n \"hips\": $fa-var-hips,\n \"css\": $fa-var-css,\n \"behance\": $fa-var-behance,\n \"reddit\": $fa-var-reddit,\n \"discord\": $fa-var-discord,\n \"chrome\": $fa-var-chrome,\n \"app-store-ios\": $fa-var-app-store-ios,\n \"cc-discover\": $fa-var-cc-discover,\n \"wpbeginner\": $fa-var-wpbeginner,\n \"confluence\": $fa-var-confluence,\n \"shoelace\": $fa-var-shoelace,\n \"mdb\": $fa-var-mdb,\n \"dochub\": $fa-var-dochub,\n \"accessible-icon\": $fa-var-accessible-icon,\n \"ebay\": $fa-var-ebay,\n \"amazon\": $fa-var-amazon,\n \"unsplash\": $fa-var-unsplash,\n \"yarn\": $fa-var-yarn,\n \"square-steam\": $fa-var-square-steam,\n \"steam-square\": $fa-var-steam-square,\n \"500px\": $fa-var-500px,\n \"square-vimeo\": $fa-var-square-vimeo,\n \"vimeo-square\": $fa-var-vimeo-square,\n \"asymmetrik\": $fa-var-asymmetrik,\n \"font-awesome\": $fa-var-font-awesome,\n \"font-awesome-flag\": $fa-var-font-awesome-flag,\n \"font-awesome-logo-full\": $fa-var-font-awesome-logo-full,\n \"gratipay\": $fa-var-gratipay,\n \"apple\": $fa-var-apple,\n \"hive\": $fa-var-hive,\n \"gitkraken\": $fa-var-gitkraken,\n \"keybase\": $fa-var-keybase,\n \"apple-pay\": $fa-var-apple-pay,\n \"padlet\": $fa-var-padlet,\n \"amazon-pay\": $fa-var-amazon-pay,\n \"square-github\": $fa-var-square-github,\n \"github-square\": $fa-var-github-square,\n \"stumbleupon\": $fa-var-stumbleupon,\n \"fedex\": $fa-var-fedex,\n \"phoenix-framework\": $fa-var-phoenix-framework,\n \"shopify\": $fa-var-shopify,\n \"neos\": $fa-var-neos,\n \"square-threads\": $fa-var-square-threads,\n \"hackerrank\": $fa-var-hackerrank,\n \"researchgate\": $fa-var-researchgate,\n \"swift\": $fa-var-swift,\n \"angular\": $fa-var-angular,\n \"speakap\": $fa-var-speakap,\n \"angrycreative\": $fa-var-angrycreative,\n \"y-combinator\": $fa-var-y-combinator,\n \"empire\": $fa-var-empire,\n \"envira\": $fa-var-envira,\n \"google-scholar\": $fa-var-google-scholar,\n \"square-gitlab\": $fa-var-square-gitlab,\n \"gitlab-square\": $fa-var-gitlab-square,\n \"studiovinari\": $fa-var-studiovinari,\n \"pied-piper\": $fa-var-pied-piper,\n \"wordpress\": $fa-var-wordpress,\n \"product-hunt\": $fa-var-product-hunt,\n \"firefox\": $fa-var-firefox,\n \"linode\": $fa-var-linode,\n \"goodreads\": $fa-var-goodreads,\n \"square-odnoklassniki\": $fa-var-square-odnoklassniki,\n \"odnoklassniki-square\": $fa-var-odnoklassniki-square,\n \"jsfiddle\": $fa-var-jsfiddle,\n \"sith\": $fa-var-sith,\n \"themeisle\": $fa-var-themeisle,\n \"page4\": $fa-var-page4,\n \"hashnode\": $fa-var-hashnode,\n \"react\": $fa-var-react,\n \"cc-paypal\": $fa-var-cc-paypal,\n \"squarespace\": $fa-var-squarespace,\n \"cc-stripe\": $fa-var-cc-stripe,\n \"creative-commons-share\": $fa-var-creative-commons-share,\n \"bitcoin\": $fa-var-bitcoin,\n \"keycdn\": $fa-var-keycdn,\n \"opera\": $fa-var-opera,\n \"itch-io\": $fa-var-itch-io,\n \"umbraco\": $fa-var-umbraco,\n \"galactic-senate\": $fa-var-galactic-senate,\n \"ubuntu\": $fa-var-ubuntu,\n \"draft2digital\": $fa-var-draft2digital,\n \"stripe\": $fa-var-stripe,\n \"houzz\": $fa-var-houzz,\n \"gg\": $fa-var-gg,\n \"dhl\": $fa-var-dhl,\n \"square-pinterest\": $fa-var-square-pinterest,\n \"pinterest-square\": $fa-var-pinterest-square,\n \"xing\": $fa-var-xing,\n \"blackberry\": $fa-var-blackberry,\n \"creative-commons-pd\": $fa-var-creative-commons-pd,\n \"playstation\": $fa-var-playstation,\n \"quinscape\": $fa-var-quinscape,\n \"less\": $fa-var-less,\n \"blogger-b\": $fa-var-blogger-b,\n \"opencart\": $fa-var-opencart,\n \"vine\": $fa-var-vine,\n \"signal-messenger\": $fa-var-signal-messenger,\n \"paypal\": $fa-var-paypal,\n \"gitlab\": $fa-var-gitlab,\n \"typo3\": $fa-var-typo3,\n \"reddit-alien\": $fa-var-reddit-alien,\n \"yahoo\": $fa-var-yahoo,\n \"dailymotion\": $fa-var-dailymotion,\n \"affiliatetheme\": $fa-var-affiliatetheme,\n \"pied-piper-pp\": $fa-var-pied-piper-pp,\n \"bootstrap\": $fa-var-bootstrap,\n \"odnoklassniki\": $fa-var-odnoklassniki,\n \"nfc-symbol\": $fa-var-nfc-symbol,\n \"mintbit\": $fa-var-mintbit,\n \"ethereum\": $fa-var-ethereum,\n \"speaker-deck\": $fa-var-speaker-deck,\n \"creative-commons-nc-eu\": $fa-var-creative-commons-nc-eu,\n \"patreon\": $fa-var-patreon,\n \"avianex\": $fa-var-avianex,\n \"ello\": $fa-var-ello,\n \"gofore\": $fa-var-gofore,\n \"bimobject\": $fa-var-bimobject,\n \"brave-reverse\": $fa-var-brave-reverse,\n \"facebook-f\": $fa-var-facebook-f,\n \"square-google-plus\": $fa-var-square-google-plus,\n \"google-plus-square\": $fa-var-google-plus-square,\n \"web-awesome\": $fa-var-web-awesome,\n \"mandalorian\": $fa-var-mandalorian,\n \"first-order-alt\": $fa-var-first-order-alt,\n \"osi\": $fa-var-osi,\n \"google-wallet\": $fa-var-google-wallet,\n \"d-and-d-beyond\": $fa-var-d-and-d-beyond,\n \"periscope\": $fa-var-periscope,\n \"fulcrum\": $fa-var-fulcrum,\n \"cloudscale\": $fa-var-cloudscale,\n \"forumbee\": $fa-var-forumbee,\n \"mizuni\": $fa-var-mizuni,\n \"schlix\": $fa-var-schlix,\n \"square-xing\": $fa-var-square-xing,\n \"xing-square\": $fa-var-xing-square,\n \"bandcamp\": $fa-var-bandcamp,\n \"wpforms\": $fa-var-wpforms,\n \"cloudversify\": $fa-var-cloudversify,\n \"usps\": $fa-var-usps,\n \"megaport\": $fa-var-megaport,\n \"magento\": $fa-var-magento,\n \"spotify\": $fa-var-spotify,\n \"optin-monster\": $fa-var-optin-monster,\n \"fly\": $fa-var-fly,\n \"square-bluesky\": $fa-var-square-bluesky,\n \"aviato\": $fa-var-aviato,\n \"itunes\": $fa-var-itunes,\n \"cuttlefish\": $fa-var-cuttlefish,\n \"blogger\": $fa-var-blogger,\n \"flickr\": $fa-var-flickr,\n \"viber\": $fa-var-viber,\n \"soundcloud\": $fa-var-soundcloud,\n \"digg\": $fa-var-digg,\n \"tencent-weibo\": $fa-var-tencent-weibo,\n \"letterboxd\": $fa-var-letterboxd,\n \"symfony\": $fa-var-symfony,\n \"maxcdn\": $fa-var-maxcdn,\n \"etsy\": $fa-var-etsy,\n \"facebook-messenger\": $fa-var-facebook-messenger,\n \"audible\": $fa-var-audible,\n \"think-peaks\": $fa-var-think-peaks,\n \"bilibili\": $fa-var-bilibili,\n \"erlang\": $fa-var-erlang,\n \"x-twitter\": $fa-var-x-twitter,\n \"cotton-bureau\": $fa-var-cotton-bureau,\n \"dashcube\": $fa-var-dashcube,\n \"42-group\": $fa-var-42-group,\n \"innosoft\": $fa-var-innosoft,\n \"stack-exchange\": $fa-var-stack-exchange,\n \"elementor\": $fa-var-elementor,\n \"square-pied-piper\": $fa-var-square-pied-piper,\n \"pied-piper-square\": $fa-var-pied-piper-square,\n \"creative-commons-nd\": $fa-var-creative-commons-nd,\n \"palfed\": $fa-var-palfed,\n \"superpowers\": $fa-var-superpowers,\n \"resolving\": $fa-var-resolving,\n \"xbox\": $fa-var-xbox,\n \"square-web-awesome-stroke\": $fa-var-square-web-awesome-stroke,\n \"searchengin\": $fa-var-searchengin,\n \"tiktok\": $fa-var-tiktok,\n \"square-facebook\": $fa-var-square-facebook,\n \"facebook-square\": $fa-var-facebook-square,\n \"renren\": $fa-var-renren,\n \"linux\": $fa-var-linux,\n \"glide\": $fa-var-glide,\n \"linkedin\": $fa-var-linkedin,\n \"hubspot\": $fa-var-hubspot,\n \"deploydog\": $fa-var-deploydog,\n \"twitch\": $fa-var-twitch,\n \"flutter\": $fa-var-flutter,\n \"ravelry\": $fa-var-ravelry,\n \"mixer\": $fa-var-mixer,\n \"square-lastfm\": $fa-var-square-lastfm,\n \"lastfm-square\": $fa-var-lastfm-square,\n \"vimeo\": $fa-var-vimeo,\n \"mendeley\": $fa-var-mendeley,\n \"uniregistry\": $fa-var-uniregistry,\n \"figma\": $fa-var-figma,\n \"creative-commons-remix\": $fa-var-creative-commons-remix,\n \"cc-amazon-pay\": $fa-var-cc-amazon-pay,\n \"dropbox\": $fa-var-dropbox,\n \"instagram\": $fa-var-instagram,\n \"cmplid\": $fa-var-cmplid,\n \"upwork\": $fa-var-upwork,\n \"facebook\": $fa-var-facebook,\n \"gripfire\": $fa-var-gripfire,\n \"jedi-order\": $fa-var-jedi-order,\n \"uikit\": $fa-var-uikit,\n \"fort-awesome-alt\": $fa-var-fort-awesome-alt,\n \"phabricator\": $fa-var-phabricator,\n \"ussunnah\": $fa-var-ussunnah,\n \"earlybirds\": $fa-var-earlybirds,\n \"trade-federation\": $fa-var-trade-federation,\n \"autoprefixer\": $fa-var-autoprefixer,\n \"whatsapp\": $fa-var-whatsapp,\n \"square-upwork\": $fa-var-square-upwork,\n \"slideshare\": $fa-var-slideshare,\n \"google-play\": $fa-var-google-play,\n \"viadeo\": $fa-var-viadeo,\n \"line\": $fa-var-line,\n \"google-drive\": $fa-var-google-drive,\n \"servicestack\": $fa-var-servicestack,\n \"simplybuilt\": $fa-var-simplybuilt,\n \"bitbucket\": $fa-var-bitbucket,\n \"imdb\": $fa-var-imdb,\n \"deezer\": $fa-var-deezer,\n \"raspberry-pi\": $fa-var-raspberry-pi,\n \"jira\": $fa-var-jira,\n \"docker\": $fa-var-docker,\n \"screenpal\": $fa-var-screenpal,\n \"bluetooth\": $fa-var-bluetooth,\n \"gitter\": $fa-var-gitter,\n \"d-and-d\": $fa-var-d-and-d,\n \"microblog\": $fa-var-microblog,\n \"cc-diners-club\": $fa-var-cc-diners-club,\n \"gg-circle\": $fa-var-gg-circle,\n \"pied-piper-hat\": $fa-var-pied-piper-hat,\n \"kickstarter-k\": $fa-var-kickstarter-k,\n \"yandex\": $fa-var-yandex,\n \"readme\": $fa-var-readme,\n \"html5\": $fa-var-html5,\n \"sellsy\": $fa-var-sellsy,\n \"square-web-awesome\": $fa-var-square-web-awesome,\n \"sass\": $fa-var-sass,\n \"wirsindhandwerk\": $fa-var-wirsindhandwerk,\n \"wsh\": $fa-var-wsh,\n \"buromobelexperte\": $fa-var-buromobelexperte,\n \"salesforce\": $fa-var-salesforce,\n \"octopus-deploy\": $fa-var-octopus-deploy,\n \"medapps\": $fa-var-medapps,\n \"ns8\": $fa-var-ns8,\n \"pinterest-p\": $fa-var-pinterest-p,\n \"apper\": $fa-var-apper,\n \"fort-awesome\": $fa-var-fort-awesome,\n \"waze\": $fa-var-waze,\n \"bluesky\": $fa-var-bluesky,\n \"cc-jcb\": $fa-var-cc-jcb,\n \"snapchat\": $fa-var-snapchat,\n \"snapchat-ghost\": $fa-var-snapchat-ghost,\n \"fantasy-flight-games\": $fa-var-fantasy-flight-games,\n \"rust\": $fa-var-rust,\n \"wix\": $fa-var-wix,\n \"square-behance\": $fa-var-square-behance,\n \"behance-square\": $fa-var-behance-square,\n \"supple\": $fa-var-supple,\n \"webflow\": $fa-var-webflow,\n \"rebel\": $fa-var-rebel,\n \"css3\": $fa-var-css3,\n \"staylinked\": $fa-var-staylinked,\n \"kaggle\": $fa-var-kaggle,\n \"space-awesome\": $fa-var-space-awesome,\n \"deviantart\": $fa-var-deviantart,\n \"cpanel\": $fa-var-cpanel,\n \"goodreads-g\": $fa-var-goodreads-g,\n \"square-git\": $fa-var-square-git,\n \"git-square\": $fa-var-git-square,\n \"square-tumblr\": $fa-var-square-tumblr,\n \"tumblr-square\": $fa-var-tumblr-square,\n \"trello\": $fa-var-trello,\n \"creative-commons-nc-jp\": $fa-var-creative-commons-nc-jp,\n \"get-pocket\": $fa-var-get-pocket,\n \"perbyte\": $fa-var-perbyte,\n \"grunt\": $fa-var-grunt,\n \"weebly\": $fa-var-weebly,\n \"connectdevelop\": $fa-var-connectdevelop,\n \"leanpub\": $fa-var-leanpub,\n \"black-tie\": $fa-var-black-tie,\n \"themeco\": $fa-var-themeco,\n \"python\": $fa-var-python,\n \"android\": $fa-var-android,\n \"bots\": $fa-var-bots,\n \"free-code-camp\": $fa-var-free-code-camp,\n \"hornbill\": $fa-var-hornbill,\n \"js\": $fa-var-js,\n \"ideal\": $fa-var-ideal,\n \"git\": $fa-var-git,\n \"dev\": $fa-var-dev,\n \"sketch\": $fa-var-sketch,\n \"yandex-international\": $fa-var-yandex-international,\n \"cc-amex\": $fa-var-cc-amex,\n \"uber\": $fa-var-uber,\n \"github\": $fa-var-github,\n \"php\": $fa-var-php,\n \"alipay\": $fa-var-alipay,\n \"youtube\": $fa-var-youtube,\n \"skyatlas\": $fa-var-skyatlas,\n \"firefox-browser\": $fa-var-firefox-browser,\n \"replyd\": $fa-var-replyd,\n \"suse\": $fa-var-suse,\n \"jenkins\": $fa-var-jenkins,\n \"twitter\": $fa-var-twitter,\n \"rockrms\": $fa-var-rockrms,\n \"pinterest\": $fa-var-pinterest,\n \"buffer\": $fa-var-buffer,\n \"npm\": $fa-var-npm,\n \"yammer\": $fa-var-yammer,\n \"btc\": $fa-var-btc,\n \"dribbble\": $fa-var-dribbble,\n \"stumbleupon-circle\": $fa-var-stumbleupon-circle,\n \"internet-explorer\": $fa-var-internet-explorer,\n \"stubber\": $fa-var-stubber,\n \"telegram\": $fa-var-telegram,\n \"telegram-plane\": $fa-var-telegram-plane,\n \"old-republic\": $fa-var-old-republic,\n \"odysee\": $fa-var-odysee,\n \"square-whatsapp\": $fa-var-square-whatsapp,\n \"whatsapp-square\": $fa-var-whatsapp-square,\n \"node-js\": $fa-var-node-js,\n \"edge-legacy\": $fa-var-edge-legacy,\n \"slack\": $fa-var-slack,\n \"slack-hash\": $fa-var-slack-hash,\n \"medrt\": $fa-var-medrt,\n \"usb\": $fa-var-usb,\n \"tumblr\": $fa-var-tumblr,\n \"vaadin\": $fa-var-vaadin,\n \"quora\": $fa-var-quora,\n \"square-x-twitter\": $fa-var-square-x-twitter,\n \"reacteurope\": $fa-var-reacteurope,\n \"medium\": $fa-var-medium,\n \"medium-m\": $fa-var-medium-m,\n \"amilia\": $fa-var-amilia,\n \"mixcloud\": $fa-var-mixcloud,\n \"flipboard\": $fa-var-flipboard,\n \"viacoin\": $fa-var-viacoin,\n \"critical-role\": $fa-var-critical-role,\n \"sitrox\": $fa-var-sitrox,\n \"discourse\": $fa-var-discourse,\n \"joomla\": $fa-var-joomla,\n \"mastodon\": $fa-var-mastodon,\n \"airbnb\": $fa-var-airbnb,\n \"wolf-pack-battalion\": $fa-var-wolf-pack-battalion,\n \"buy-n-large\": $fa-var-buy-n-large,\n \"gulp\": $fa-var-gulp,\n \"creative-commons-sampling-plus\": $fa-var-creative-commons-sampling-plus,\n \"strava\": $fa-var-strava,\n \"ember\": $fa-var-ember,\n \"canadian-maple-leaf\": $fa-var-canadian-maple-leaf,\n \"teamspeak\": $fa-var-teamspeak,\n \"pushed\": $fa-var-pushed,\n \"wordpress-simple\": $fa-var-wordpress-simple,\n \"nutritionix\": $fa-var-nutritionix,\n \"wodu\": $fa-var-wodu,\n \"google-pay\": $fa-var-google-pay,\n \"intercom\": $fa-var-intercom,\n \"zhihu\": $fa-var-zhihu,\n \"korvue\": $fa-var-korvue,\n \"pix\": $fa-var-pix,\n \"steam-symbol\": $fa-var-steam-symbol,\n);\n", + "/*!\n * Font Awesome Free 6.7.1 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n * Copyright 2024 Fonticons, Inc.\n */\n@import 'functions';\n@import 'variables';\n\n:root, :host {\n --#{$fa-css-prefix}-style-family-brands: 'Font Awesome 6 Brands';\n --#{$fa-css-prefix}-font-brands: normal 400 1em/1 'Font Awesome 6 Brands';\n}\n\n@font-face {\n font-family: 'Font Awesome 6 Brands';\n font-style: normal;\n font-weight: 400;\n font-display: $fa-font-display;\n src: url('#{$fa-font-path}/fa-brands-400.woff2') format('woff2'),\n url('#{$fa-font-path}/fa-brands-400.ttf') format('truetype');\n}\n\n.fab,\n.#{$fa-css-prefix}-brands {\n font-weight: 400;\n}\n\n@each $name, $icon in $fa-brand-icons {\n .#{$fa-css-prefix}-#{$name} { #{$fa-icon-property}: unquote(\"\\\"#{ $icon }\\\"\"); }\n}\n", + "// functions\n// --------------------------\n\n// fa-content: convenience function used to set content property\n@function fa-content($fa-var) {\n @return unquote(\"\\\"#{ $fa-var }\\\"\");\n}\n\n// fa-divide: Originally obtained from the Bootstrap https://github.com/twbs/bootstrap\n//\n// Licensed under: The MIT License (MIT)\n//\n// Copyright (c) 2011-2021 Twitter, Inc.\n// Copyright (c) 2011-2021 The Bootstrap Authors\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n@function fa-divide($dividend, $divisor, $precision: 10) {\n $sign: if($dividend > 0 and $divisor > 0, 1, -1);\n $dividend: abs($dividend);\n $divisor: abs($divisor);\n $quotient: 0;\n $remainder: $dividend;\n @if $dividend == 0 {\n @return 0;\n }\n @if $divisor == 0 {\n @error \"Cannot divide by 0\";\n }\n @if $divisor == 1 {\n @return $dividend;\n }\n @while $remainder >= $divisor {\n $quotient: $quotient + 1;\n $remainder: $remainder - $divisor;\n }\n @if $remainder > 0 and $precision > 0 {\n $remainder: fa-divide($remainder * 10, $divisor, $precision - 1) * .1;\n }\n @return ($quotient + $remainder) * $sign;\n}\n", + "// variables\n// --------------------------\n\n$fa-css-prefix : fa !default;\n$fa-style : 900 !default;\n$fa-style-family : \"Font Awesome 6 Free\" !default;\n\n$fa-icon-property : --fa;\n$fa-duotone-icon-property : --fa--fa;\n\n$fa-display : inline-block !default;\n\n$fa-fw-width : fa-divide(20em, 16) !default;\n$fa-inverse : #fff !default;\n\n$fa-border-color : #eee !default;\n$fa-border-padding : .2em .25em .15em !default;\n$fa-border-radius : .1em !default;\n$fa-border-style : solid !default;\n$fa-border-width : .08em !default;\n\n$fa-size-scale-2xs : 10 !default;\n$fa-size-scale-xs : 12 !default;\n$fa-size-scale-sm : 14 !default;\n$fa-size-scale-base : 16 !default;\n$fa-size-scale-lg : 20 !default;\n$fa-size-scale-xl : 24 !default;\n$fa-size-scale-2xl : 32 !default;\n\n$fa-sizes: (\n \"2xs\" : $fa-size-scale-2xs,\n \"xs\" : $fa-size-scale-xs,\n \"sm\" : $fa-size-scale-sm,\n \"lg\" : $fa-size-scale-lg,\n \"xl\" : $fa-size-scale-xl,\n \"2xl\" : $fa-size-scale-2xl\n) !default;\n\n$fa-li-width : 2em !default;\n$fa-li-margin : $fa-li-width * fa-divide(5, 4) !default;\n\n$fa-pull-margin : .3em !default;\n\n$fa-primary-opacity : 1 !default;\n$fa-secondary-opacity : .4 !default;\n\n$fa-stack-vertical-align : middle !default;\n$fa-stack-width : ($fa-fw-width * 2) !default;\n$fa-stack-z-index : auto !default;\n\n$fa-font-display : block !default;\n$fa-font-path : \"../webfonts\" !default;\n\n$fa-var-0: \\30;\n$fa-var-1: \\31;\n$fa-var-2: \\32;\n$fa-var-3: \\33;\n$fa-var-4: \\34;\n$fa-var-5: \\35;\n$fa-var-6: \\36;\n$fa-var-7: \\37;\n$fa-var-8: \\38;\n$fa-var-9: \\39;\n$fa-var-fill-drip: \\f576;\n$fa-var-arrows-to-circle: \\e4bd;\n$fa-var-circle-chevron-right: \\f138;\n$fa-var-chevron-circle-right: \\f138;\n$fa-var-at: \\40;\n$fa-var-trash-can: \\f2ed;\n$fa-var-trash-alt: \\f2ed;\n$fa-var-text-height: \\f034;\n$fa-var-user-xmark: \\f235;\n$fa-var-user-times: \\f235;\n$fa-var-stethoscope: \\f0f1;\n$fa-var-message: \\f27a;\n$fa-var-comment-alt: \\f27a;\n$fa-var-info: \\f129;\n$fa-var-down-left-and-up-right-to-center: \\f422;\n$fa-var-compress-alt: \\f422;\n$fa-var-explosion: \\e4e9;\n$fa-var-file-lines: \\f15c;\n$fa-var-file-alt: \\f15c;\n$fa-var-file-text: \\f15c;\n$fa-var-wave-square: \\f83e;\n$fa-var-ring: \\f70b;\n$fa-var-building-un: \\e4d9;\n$fa-var-dice-three: \\f527;\n$fa-var-calendar-days: \\f073;\n$fa-var-calendar-alt: \\f073;\n$fa-var-anchor-circle-check: \\e4aa;\n$fa-var-building-circle-arrow-right: \\e4d1;\n$fa-var-volleyball: \\f45f;\n$fa-var-volleyball-ball: \\f45f;\n$fa-var-arrows-up-to-line: \\e4c2;\n$fa-var-sort-down: \\f0dd;\n$fa-var-sort-desc: \\f0dd;\n$fa-var-circle-minus: \\f056;\n$fa-var-minus-circle: \\f056;\n$fa-var-door-open: \\f52b;\n$fa-var-right-from-bracket: \\f2f5;\n$fa-var-sign-out-alt: \\f2f5;\n$fa-var-atom: \\f5d2;\n$fa-var-soap: \\e06e;\n$fa-var-icons: \\f86d;\n$fa-var-heart-music-camera-bolt: \\f86d;\n$fa-var-microphone-lines-slash: \\f539;\n$fa-var-microphone-alt-slash: \\f539;\n$fa-var-bridge-circle-check: \\e4c9;\n$fa-var-pump-medical: \\e06a;\n$fa-var-fingerprint: \\f577;\n$fa-var-hand-point-right: \\f0a4;\n$fa-var-magnifying-glass-location: \\f689;\n$fa-var-search-location: \\f689;\n$fa-var-forward-step: \\f051;\n$fa-var-step-forward: \\f051;\n$fa-var-face-smile-beam: \\f5b8;\n$fa-var-smile-beam: \\f5b8;\n$fa-var-flag-checkered: \\f11e;\n$fa-var-football: \\f44e;\n$fa-var-football-ball: \\f44e;\n$fa-var-school-circle-exclamation: \\e56c;\n$fa-var-crop: \\f125;\n$fa-var-angles-down: \\f103;\n$fa-var-angle-double-down: \\f103;\n$fa-var-users-rectangle: \\e594;\n$fa-var-people-roof: \\e537;\n$fa-var-people-line: \\e534;\n$fa-var-beer-mug-empty: \\f0fc;\n$fa-var-beer: \\f0fc;\n$fa-var-diagram-predecessor: \\e477;\n$fa-var-arrow-up-long: \\f176;\n$fa-var-long-arrow-up: \\f176;\n$fa-var-fire-flame-simple: \\f46a;\n$fa-var-burn: \\f46a;\n$fa-var-person: \\f183;\n$fa-var-male: \\f183;\n$fa-var-laptop: \\f109;\n$fa-var-file-csv: \\f6dd;\n$fa-var-menorah: \\f676;\n$fa-var-truck-plane: \\e58f;\n$fa-var-record-vinyl: \\f8d9;\n$fa-var-face-grin-stars: \\f587;\n$fa-var-grin-stars: \\f587;\n$fa-var-bong: \\f55c;\n$fa-var-spaghetti-monster-flying: \\f67b;\n$fa-var-pastafarianism: \\f67b;\n$fa-var-arrow-down-up-across-line: \\e4af;\n$fa-var-spoon: \\f2e5;\n$fa-var-utensil-spoon: \\f2e5;\n$fa-var-jar-wheat: \\e517;\n$fa-var-envelopes-bulk: \\f674;\n$fa-var-mail-bulk: \\f674;\n$fa-var-file-circle-exclamation: \\e4eb;\n$fa-var-circle-h: \\f47e;\n$fa-var-hospital-symbol: \\f47e;\n$fa-var-pager: \\f815;\n$fa-var-address-book: \\f2b9;\n$fa-var-contact-book: \\f2b9;\n$fa-var-strikethrough: \\f0cc;\n$fa-var-k: \\4b;\n$fa-var-landmark-flag: \\e51c;\n$fa-var-pencil: \\f303;\n$fa-var-pencil-alt: \\f303;\n$fa-var-backward: \\f04a;\n$fa-var-caret-right: \\f0da;\n$fa-var-comments: \\f086;\n$fa-var-paste: \\f0ea;\n$fa-var-file-clipboard: \\f0ea;\n$fa-var-code-pull-request: \\e13c;\n$fa-var-clipboard-list: \\f46d;\n$fa-var-truck-ramp-box: \\f4de;\n$fa-var-truck-loading: \\f4de;\n$fa-var-user-check: \\f4fc;\n$fa-var-vial-virus: \\e597;\n$fa-var-sheet-plastic: \\e571;\n$fa-var-blog: \\f781;\n$fa-var-user-ninja: \\f504;\n$fa-var-person-arrow-up-from-line: \\e539;\n$fa-var-scroll-torah: \\f6a0;\n$fa-var-torah: \\f6a0;\n$fa-var-broom-ball: \\f458;\n$fa-var-quidditch: \\f458;\n$fa-var-quidditch-broom-ball: \\f458;\n$fa-var-toggle-off: \\f204;\n$fa-var-box-archive: \\f187;\n$fa-var-archive: \\f187;\n$fa-var-person-drowning: \\e545;\n$fa-var-arrow-down-9-1: \\f886;\n$fa-var-sort-numeric-desc: \\f886;\n$fa-var-sort-numeric-down-alt: \\f886;\n$fa-var-face-grin-tongue-squint: \\f58a;\n$fa-var-grin-tongue-squint: \\f58a;\n$fa-var-spray-can: \\f5bd;\n$fa-var-truck-monster: \\f63b;\n$fa-var-w: \\57;\n$fa-var-earth-africa: \\f57c;\n$fa-var-globe-africa: \\f57c;\n$fa-var-rainbow: \\f75b;\n$fa-var-circle-notch: \\f1ce;\n$fa-var-tablet-screen-button: \\f3fa;\n$fa-var-tablet-alt: \\f3fa;\n$fa-var-paw: \\f1b0;\n$fa-var-cloud: \\f0c2;\n$fa-var-trowel-bricks: \\e58a;\n$fa-var-face-flushed: \\f579;\n$fa-var-flushed: \\f579;\n$fa-var-hospital-user: \\f80d;\n$fa-var-tent-arrow-left-right: \\e57f;\n$fa-var-gavel: \\f0e3;\n$fa-var-legal: \\f0e3;\n$fa-var-binoculars: \\f1e5;\n$fa-var-microphone-slash: \\f131;\n$fa-var-box-tissue: \\e05b;\n$fa-var-motorcycle: \\f21c;\n$fa-var-bell-concierge: \\f562;\n$fa-var-concierge-bell: \\f562;\n$fa-var-pen-ruler: \\f5ae;\n$fa-var-pencil-ruler: \\f5ae;\n$fa-var-people-arrows: \\e068;\n$fa-var-people-arrows-left-right: \\e068;\n$fa-var-mars-and-venus-burst: \\e523;\n$fa-var-square-caret-right: \\f152;\n$fa-var-caret-square-right: \\f152;\n$fa-var-scissors: \\f0c4;\n$fa-var-cut: \\f0c4;\n$fa-var-sun-plant-wilt: \\e57a;\n$fa-var-toilets-portable: \\e584;\n$fa-var-hockey-puck: \\f453;\n$fa-var-table: \\f0ce;\n$fa-var-magnifying-glass-arrow-right: \\e521;\n$fa-var-tachograph-digital: \\f566;\n$fa-var-digital-tachograph: \\f566;\n$fa-var-users-slash: \\e073;\n$fa-var-clover: \\e139;\n$fa-var-reply: \\f3e5;\n$fa-var-mail-reply: \\f3e5;\n$fa-var-star-and-crescent: \\f699;\n$fa-var-house-fire: \\e50c;\n$fa-var-square-minus: \\f146;\n$fa-var-minus-square: \\f146;\n$fa-var-helicopter: \\f533;\n$fa-var-compass: \\f14e;\n$fa-var-square-caret-down: \\f150;\n$fa-var-caret-square-down: \\f150;\n$fa-var-file-circle-question: \\e4ef;\n$fa-var-laptop-code: \\f5fc;\n$fa-var-swatchbook: \\f5c3;\n$fa-var-prescription-bottle: \\f485;\n$fa-var-bars: \\f0c9;\n$fa-var-navicon: \\f0c9;\n$fa-var-people-group: \\e533;\n$fa-var-hourglass-end: \\f253;\n$fa-var-hourglass-3: \\f253;\n$fa-var-heart-crack: \\f7a9;\n$fa-var-heart-broken: \\f7a9;\n$fa-var-square-up-right: \\f360;\n$fa-var-external-link-square-alt: \\f360;\n$fa-var-face-kiss-beam: \\f597;\n$fa-var-kiss-beam: \\f597;\n$fa-var-film: \\f008;\n$fa-var-ruler-horizontal: \\f547;\n$fa-var-people-robbery: \\e536;\n$fa-var-lightbulb: \\f0eb;\n$fa-var-caret-left: \\f0d9;\n$fa-var-circle-exclamation: \\f06a;\n$fa-var-exclamation-circle: \\f06a;\n$fa-var-school-circle-xmark: \\e56d;\n$fa-var-arrow-right-from-bracket: \\f08b;\n$fa-var-sign-out: \\f08b;\n$fa-var-circle-chevron-down: \\f13a;\n$fa-var-chevron-circle-down: \\f13a;\n$fa-var-unlock-keyhole: \\f13e;\n$fa-var-unlock-alt: \\f13e;\n$fa-var-cloud-showers-heavy: \\f740;\n$fa-var-headphones-simple: \\f58f;\n$fa-var-headphones-alt: \\f58f;\n$fa-var-sitemap: \\f0e8;\n$fa-var-circle-dollar-to-slot: \\f4b9;\n$fa-var-donate: \\f4b9;\n$fa-var-memory: \\f538;\n$fa-var-road-spikes: \\e568;\n$fa-var-fire-burner: \\e4f1;\n$fa-var-flag: \\f024;\n$fa-var-hanukiah: \\f6e6;\n$fa-var-feather: \\f52d;\n$fa-var-volume-low: \\f027;\n$fa-var-volume-down: \\f027;\n$fa-var-comment-slash: \\f4b3;\n$fa-var-cloud-sun-rain: \\f743;\n$fa-var-compress: \\f066;\n$fa-var-wheat-awn: \\e2cd;\n$fa-var-wheat-alt: \\e2cd;\n$fa-var-ankh: \\f644;\n$fa-var-hands-holding-child: \\e4fa;\n$fa-var-asterisk: \\2a;\n$fa-var-square-check: \\f14a;\n$fa-var-check-square: \\f14a;\n$fa-var-peseta-sign: \\e221;\n$fa-var-heading: \\f1dc;\n$fa-var-header: \\f1dc;\n$fa-var-ghost: \\f6e2;\n$fa-var-list: \\f03a;\n$fa-var-list-squares: \\f03a;\n$fa-var-square-phone-flip: \\f87b;\n$fa-var-phone-square-alt: \\f87b;\n$fa-var-cart-plus: \\f217;\n$fa-var-gamepad: \\f11b;\n$fa-var-circle-dot: \\f192;\n$fa-var-dot-circle: \\f192;\n$fa-var-face-dizzy: \\f567;\n$fa-var-dizzy: \\f567;\n$fa-var-egg: \\f7fb;\n$fa-var-house-medical-circle-xmark: \\e513;\n$fa-var-campground: \\f6bb;\n$fa-var-folder-plus: \\f65e;\n$fa-var-futbol: \\f1e3;\n$fa-var-futbol-ball: \\f1e3;\n$fa-var-soccer-ball: \\f1e3;\n$fa-var-paintbrush: \\f1fc;\n$fa-var-paint-brush: \\f1fc;\n$fa-var-lock: \\f023;\n$fa-var-gas-pump: \\f52f;\n$fa-var-hot-tub-person: \\f593;\n$fa-var-hot-tub: \\f593;\n$fa-var-map-location: \\f59f;\n$fa-var-map-marked: \\f59f;\n$fa-var-house-flood-water: \\e50e;\n$fa-var-tree: \\f1bb;\n$fa-var-bridge-lock: \\e4cc;\n$fa-var-sack-dollar: \\f81d;\n$fa-var-pen-to-square: \\f044;\n$fa-var-edit: \\f044;\n$fa-var-car-side: \\f5e4;\n$fa-var-share-nodes: \\f1e0;\n$fa-var-share-alt: \\f1e0;\n$fa-var-heart-circle-minus: \\e4ff;\n$fa-var-hourglass-half: \\f252;\n$fa-var-hourglass-2: \\f252;\n$fa-var-microscope: \\f610;\n$fa-var-sink: \\e06d;\n$fa-var-bag-shopping: \\f290;\n$fa-var-shopping-bag: \\f290;\n$fa-var-arrow-down-z-a: \\f881;\n$fa-var-sort-alpha-desc: \\f881;\n$fa-var-sort-alpha-down-alt: \\f881;\n$fa-var-mitten: \\f7b5;\n$fa-var-person-rays: \\e54d;\n$fa-var-users: \\f0c0;\n$fa-var-eye-slash: \\f070;\n$fa-var-flask-vial: \\e4f3;\n$fa-var-hand: \\f256;\n$fa-var-hand-paper: \\f256;\n$fa-var-om: \\f679;\n$fa-var-worm: \\e599;\n$fa-var-house-circle-xmark: \\e50b;\n$fa-var-plug: \\f1e6;\n$fa-var-chevron-up: \\f077;\n$fa-var-hand-spock: \\f259;\n$fa-var-stopwatch: \\f2f2;\n$fa-var-face-kiss: \\f596;\n$fa-var-kiss: \\f596;\n$fa-var-bridge-circle-xmark: \\e4cb;\n$fa-var-face-grin-tongue: \\f589;\n$fa-var-grin-tongue: \\f589;\n$fa-var-chess-bishop: \\f43a;\n$fa-var-face-grin-wink: \\f58c;\n$fa-var-grin-wink: \\f58c;\n$fa-var-ear-deaf: \\f2a4;\n$fa-var-deaf: \\f2a4;\n$fa-var-deafness: \\f2a4;\n$fa-var-hard-of-hearing: \\f2a4;\n$fa-var-road-circle-check: \\e564;\n$fa-var-dice-five: \\f523;\n$fa-var-square-rss: \\f143;\n$fa-var-rss-square: \\f143;\n$fa-var-land-mine-on: \\e51b;\n$fa-var-i-cursor: \\f246;\n$fa-var-stamp: \\f5bf;\n$fa-var-stairs: \\e289;\n$fa-var-i: \\49;\n$fa-var-hryvnia-sign: \\f6f2;\n$fa-var-hryvnia: \\f6f2;\n$fa-var-pills: \\f484;\n$fa-var-face-grin-wide: \\f581;\n$fa-var-grin-alt: \\f581;\n$fa-var-tooth: \\f5c9;\n$fa-var-v: \\56;\n$fa-var-bangladeshi-taka-sign: \\e2e6;\n$fa-var-bicycle: \\f206;\n$fa-var-staff-snake: \\e579;\n$fa-var-rod-asclepius: \\e579;\n$fa-var-rod-snake: \\e579;\n$fa-var-staff-aesculapius: \\e579;\n$fa-var-head-side-cough-slash: \\e062;\n$fa-var-truck-medical: \\f0f9;\n$fa-var-ambulance: \\f0f9;\n$fa-var-wheat-awn-circle-exclamation: \\e598;\n$fa-var-snowman: \\f7d0;\n$fa-var-mortar-pestle: \\f5a7;\n$fa-var-road-barrier: \\e562;\n$fa-var-school: \\f549;\n$fa-var-igloo: \\f7ae;\n$fa-var-joint: \\f595;\n$fa-var-angle-right: \\f105;\n$fa-var-horse: \\f6f0;\n$fa-var-q: \\51;\n$fa-var-g: \\47;\n$fa-var-notes-medical: \\f481;\n$fa-var-temperature-half: \\f2c9;\n$fa-var-temperature-2: \\f2c9;\n$fa-var-thermometer-2: \\f2c9;\n$fa-var-thermometer-half: \\f2c9;\n$fa-var-dong-sign: \\e169;\n$fa-var-capsules: \\f46b;\n$fa-var-poo-storm: \\f75a;\n$fa-var-poo-bolt: \\f75a;\n$fa-var-face-frown-open: \\f57a;\n$fa-var-frown-open: \\f57a;\n$fa-var-hand-point-up: \\f0a6;\n$fa-var-money-bill: \\f0d6;\n$fa-var-bookmark: \\f02e;\n$fa-var-align-justify: \\f039;\n$fa-var-umbrella-beach: \\f5ca;\n$fa-var-helmet-un: \\e503;\n$fa-var-bullseye: \\f140;\n$fa-var-bacon: \\f7e5;\n$fa-var-hand-point-down: \\f0a7;\n$fa-var-arrow-up-from-bracket: \\e09a;\n$fa-var-folder: \\f07b;\n$fa-var-folder-blank: \\f07b;\n$fa-var-file-waveform: \\f478;\n$fa-var-file-medical-alt: \\f478;\n$fa-var-radiation: \\f7b9;\n$fa-var-chart-simple: \\e473;\n$fa-var-mars-stroke: \\f229;\n$fa-var-vial: \\f492;\n$fa-var-gauge: \\f624;\n$fa-var-dashboard: \\f624;\n$fa-var-gauge-med: \\f624;\n$fa-var-tachometer-alt-average: \\f624;\n$fa-var-wand-magic-sparkles: \\e2ca;\n$fa-var-magic-wand-sparkles: \\e2ca;\n$fa-var-e: \\45;\n$fa-var-pen-clip: \\f305;\n$fa-var-pen-alt: \\f305;\n$fa-var-bridge-circle-exclamation: \\e4ca;\n$fa-var-user: \\f007;\n$fa-var-school-circle-check: \\e56b;\n$fa-var-dumpster: \\f793;\n$fa-var-van-shuttle: \\f5b6;\n$fa-var-shuttle-van: \\f5b6;\n$fa-var-building-user: \\e4da;\n$fa-var-square-caret-left: \\f191;\n$fa-var-caret-square-left: \\f191;\n$fa-var-highlighter: \\f591;\n$fa-var-key: \\f084;\n$fa-var-bullhorn: \\f0a1;\n$fa-var-globe: \\f0ac;\n$fa-var-synagogue: \\f69b;\n$fa-var-person-half-dress: \\e548;\n$fa-var-road-bridge: \\e563;\n$fa-var-location-arrow: \\f124;\n$fa-var-c: \\43;\n$fa-var-tablet-button: \\f10a;\n$fa-var-building-lock: \\e4d6;\n$fa-var-pizza-slice: \\f818;\n$fa-var-money-bill-wave: \\f53a;\n$fa-var-chart-area: \\f1fe;\n$fa-var-area-chart: \\f1fe;\n$fa-var-house-flag: \\e50d;\n$fa-var-person-circle-minus: \\e540;\n$fa-var-ban: \\f05e;\n$fa-var-cancel: \\f05e;\n$fa-var-camera-rotate: \\e0d8;\n$fa-var-spray-can-sparkles: \\f5d0;\n$fa-var-air-freshener: \\f5d0;\n$fa-var-star: \\f005;\n$fa-var-repeat: \\f363;\n$fa-var-cross: \\f654;\n$fa-var-box: \\f466;\n$fa-var-venus-mars: \\f228;\n$fa-var-arrow-pointer: \\f245;\n$fa-var-mouse-pointer: \\f245;\n$fa-var-maximize: \\f31e;\n$fa-var-expand-arrows-alt: \\f31e;\n$fa-var-charging-station: \\f5e7;\n$fa-var-shapes: \\f61f;\n$fa-var-triangle-circle-square: \\f61f;\n$fa-var-shuffle: \\f074;\n$fa-var-random: \\f074;\n$fa-var-person-running: \\f70c;\n$fa-var-running: \\f70c;\n$fa-var-mobile-retro: \\e527;\n$fa-var-grip-lines-vertical: \\f7a5;\n$fa-var-spider: \\f717;\n$fa-var-hands-bound: \\e4f9;\n$fa-var-file-invoice-dollar: \\f571;\n$fa-var-plane-circle-exclamation: \\e556;\n$fa-var-x-ray: \\f497;\n$fa-var-spell-check: \\f891;\n$fa-var-slash: \\f715;\n$fa-var-computer-mouse: \\f8cc;\n$fa-var-mouse: \\f8cc;\n$fa-var-arrow-right-to-bracket: \\f090;\n$fa-var-sign-in: \\f090;\n$fa-var-shop-slash: \\e070;\n$fa-var-store-alt-slash: \\e070;\n$fa-var-server: \\f233;\n$fa-var-virus-covid-slash: \\e4a9;\n$fa-var-shop-lock: \\e4a5;\n$fa-var-hourglass-start: \\f251;\n$fa-var-hourglass-1: \\f251;\n$fa-var-blender-phone: \\f6b6;\n$fa-var-building-wheat: \\e4db;\n$fa-var-person-breastfeeding: \\e53a;\n$fa-var-right-to-bracket: \\f2f6;\n$fa-var-sign-in-alt: \\f2f6;\n$fa-var-venus: \\f221;\n$fa-var-passport: \\f5ab;\n$fa-var-thumbtack-slash: \\e68f;\n$fa-var-thumb-tack-slash: \\e68f;\n$fa-var-heart-pulse: \\f21e;\n$fa-var-heartbeat: \\f21e;\n$fa-var-people-carry-box: \\f4ce;\n$fa-var-people-carry: \\f4ce;\n$fa-var-temperature-high: \\f769;\n$fa-var-microchip: \\f2db;\n$fa-var-crown: \\f521;\n$fa-var-weight-hanging: \\f5cd;\n$fa-var-xmarks-lines: \\e59a;\n$fa-var-file-prescription: \\f572;\n$fa-var-weight-scale: \\f496;\n$fa-var-weight: \\f496;\n$fa-var-user-group: \\f500;\n$fa-var-user-friends: \\f500;\n$fa-var-arrow-up-a-z: \\f15e;\n$fa-var-sort-alpha-up: \\f15e;\n$fa-var-chess-knight: \\f441;\n$fa-var-face-laugh-squint: \\f59b;\n$fa-var-laugh-squint: \\f59b;\n$fa-var-wheelchair: \\f193;\n$fa-var-circle-arrow-up: \\f0aa;\n$fa-var-arrow-circle-up: \\f0aa;\n$fa-var-toggle-on: \\f205;\n$fa-var-person-walking: \\f554;\n$fa-var-walking: \\f554;\n$fa-var-l: \\4c;\n$fa-var-fire: \\f06d;\n$fa-var-bed-pulse: \\f487;\n$fa-var-procedures: \\f487;\n$fa-var-shuttle-space: \\f197;\n$fa-var-space-shuttle: \\f197;\n$fa-var-face-laugh: \\f599;\n$fa-var-laugh: \\f599;\n$fa-var-folder-open: \\f07c;\n$fa-var-heart-circle-plus: \\e500;\n$fa-var-code-fork: \\e13b;\n$fa-var-city: \\f64f;\n$fa-var-microphone-lines: \\f3c9;\n$fa-var-microphone-alt: \\f3c9;\n$fa-var-pepper-hot: \\f816;\n$fa-var-unlock: \\f09c;\n$fa-var-colon-sign: \\e140;\n$fa-var-headset: \\f590;\n$fa-var-store-slash: \\e071;\n$fa-var-road-circle-xmark: \\e566;\n$fa-var-user-minus: \\f503;\n$fa-var-mars-stroke-up: \\f22a;\n$fa-var-mars-stroke-v: \\f22a;\n$fa-var-champagne-glasses: \\f79f;\n$fa-var-glass-cheers: \\f79f;\n$fa-var-clipboard: \\f328;\n$fa-var-house-circle-exclamation: \\e50a;\n$fa-var-file-arrow-up: \\f574;\n$fa-var-file-upload: \\f574;\n$fa-var-wifi: \\f1eb;\n$fa-var-wifi-3: \\f1eb;\n$fa-var-wifi-strong: \\f1eb;\n$fa-var-bath: \\f2cd;\n$fa-var-bathtub: \\f2cd;\n$fa-var-underline: \\f0cd;\n$fa-var-user-pen: \\f4ff;\n$fa-var-user-edit: \\f4ff;\n$fa-var-signature: \\f5b7;\n$fa-var-stroopwafel: \\f551;\n$fa-var-bold: \\f032;\n$fa-var-anchor-lock: \\e4ad;\n$fa-var-building-ngo: \\e4d7;\n$fa-var-manat-sign: \\e1d5;\n$fa-var-not-equal: \\f53e;\n$fa-var-border-top-left: \\f853;\n$fa-var-border-style: \\f853;\n$fa-var-map-location-dot: \\f5a0;\n$fa-var-map-marked-alt: \\f5a0;\n$fa-var-jedi: \\f669;\n$fa-var-square-poll-vertical: \\f681;\n$fa-var-poll: \\f681;\n$fa-var-mug-hot: \\f7b6;\n$fa-var-car-battery: \\f5df;\n$fa-var-battery-car: \\f5df;\n$fa-var-gift: \\f06b;\n$fa-var-dice-two: \\f528;\n$fa-var-chess-queen: \\f445;\n$fa-var-glasses: \\f530;\n$fa-var-chess-board: \\f43c;\n$fa-var-building-circle-check: \\e4d2;\n$fa-var-person-chalkboard: \\e53d;\n$fa-var-mars-stroke-right: \\f22b;\n$fa-var-mars-stroke-h: \\f22b;\n$fa-var-hand-back-fist: \\f255;\n$fa-var-hand-rock: \\f255;\n$fa-var-square-caret-up: \\f151;\n$fa-var-caret-square-up: \\f151;\n$fa-var-cloud-showers-water: \\e4e4;\n$fa-var-chart-bar: \\f080;\n$fa-var-bar-chart: \\f080;\n$fa-var-hands-bubbles: \\e05e;\n$fa-var-hands-wash: \\e05e;\n$fa-var-less-than-equal: \\f537;\n$fa-var-train: \\f238;\n$fa-var-eye-low-vision: \\f2a8;\n$fa-var-low-vision: \\f2a8;\n$fa-var-crow: \\f520;\n$fa-var-sailboat: \\e445;\n$fa-var-window-restore: \\f2d2;\n$fa-var-square-plus: \\f0fe;\n$fa-var-plus-square: \\f0fe;\n$fa-var-torii-gate: \\f6a1;\n$fa-var-frog: \\f52e;\n$fa-var-bucket: \\e4cf;\n$fa-var-image: \\f03e;\n$fa-var-microphone: \\f130;\n$fa-var-cow: \\f6c8;\n$fa-var-caret-up: \\f0d8;\n$fa-var-screwdriver: \\f54a;\n$fa-var-folder-closed: \\e185;\n$fa-var-house-tsunami: \\e515;\n$fa-var-square-nfi: \\e576;\n$fa-var-arrow-up-from-ground-water: \\e4b5;\n$fa-var-martini-glass: \\f57b;\n$fa-var-glass-martini-alt: \\f57b;\n$fa-var-square-binary: \\e69b;\n$fa-var-rotate-left: \\f2ea;\n$fa-var-rotate-back: \\f2ea;\n$fa-var-rotate-backward: \\f2ea;\n$fa-var-undo-alt: \\f2ea;\n$fa-var-table-columns: \\f0db;\n$fa-var-columns: \\f0db;\n$fa-var-lemon: \\f094;\n$fa-var-head-side-mask: \\e063;\n$fa-var-handshake: \\f2b5;\n$fa-var-gem: \\f3a5;\n$fa-var-dolly: \\f472;\n$fa-var-dolly-box: \\f472;\n$fa-var-smoking: \\f48d;\n$fa-var-minimize: \\f78c;\n$fa-var-compress-arrows-alt: \\f78c;\n$fa-var-monument: \\f5a6;\n$fa-var-snowplow: \\f7d2;\n$fa-var-angles-right: \\f101;\n$fa-var-angle-double-right: \\f101;\n$fa-var-cannabis: \\f55f;\n$fa-var-circle-play: \\f144;\n$fa-var-play-circle: \\f144;\n$fa-var-tablets: \\f490;\n$fa-var-ethernet: \\f796;\n$fa-var-euro-sign: \\f153;\n$fa-var-eur: \\f153;\n$fa-var-euro: \\f153;\n$fa-var-chair: \\f6c0;\n$fa-var-circle-check: \\f058;\n$fa-var-check-circle: \\f058;\n$fa-var-circle-stop: \\f28d;\n$fa-var-stop-circle: \\f28d;\n$fa-var-compass-drafting: \\f568;\n$fa-var-drafting-compass: \\f568;\n$fa-var-plate-wheat: \\e55a;\n$fa-var-icicles: \\f7ad;\n$fa-var-person-shelter: \\e54f;\n$fa-var-neuter: \\f22c;\n$fa-var-id-badge: \\f2c1;\n$fa-var-marker: \\f5a1;\n$fa-var-face-laugh-beam: \\f59a;\n$fa-var-laugh-beam: \\f59a;\n$fa-var-helicopter-symbol: \\e502;\n$fa-var-universal-access: \\f29a;\n$fa-var-circle-chevron-up: \\f139;\n$fa-var-chevron-circle-up: \\f139;\n$fa-var-lari-sign: \\e1c8;\n$fa-var-volcano: \\f770;\n$fa-var-person-walking-dashed-line-arrow-right: \\e553;\n$fa-var-sterling-sign: \\f154;\n$fa-var-gbp: \\f154;\n$fa-var-pound-sign: \\f154;\n$fa-var-viruses: \\e076;\n$fa-var-square-person-confined: \\e577;\n$fa-var-user-tie: \\f508;\n$fa-var-arrow-down-long: \\f175;\n$fa-var-long-arrow-down: \\f175;\n$fa-var-tent-arrow-down-to-line: \\e57e;\n$fa-var-certificate: \\f0a3;\n$fa-var-reply-all: \\f122;\n$fa-var-mail-reply-all: \\f122;\n$fa-var-suitcase: \\f0f2;\n$fa-var-person-skating: \\f7c5;\n$fa-var-skating: \\f7c5;\n$fa-var-filter-circle-dollar: \\f662;\n$fa-var-funnel-dollar: \\f662;\n$fa-var-camera-retro: \\f083;\n$fa-var-circle-arrow-down: \\f0ab;\n$fa-var-arrow-circle-down: \\f0ab;\n$fa-var-file-import: \\f56f;\n$fa-var-arrow-right-to-file: \\f56f;\n$fa-var-square-arrow-up-right: \\f14c;\n$fa-var-external-link-square: \\f14c;\n$fa-var-box-open: \\f49e;\n$fa-var-scroll: \\f70e;\n$fa-var-spa: \\f5bb;\n$fa-var-location-pin-lock: \\e51f;\n$fa-var-pause: \\f04c;\n$fa-var-hill-avalanche: \\e507;\n$fa-var-temperature-empty: \\f2cb;\n$fa-var-temperature-0: \\f2cb;\n$fa-var-thermometer-0: \\f2cb;\n$fa-var-thermometer-empty: \\f2cb;\n$fa-var-bomb: \\f1e2;\n$fa-var-registered: \\f25d;\n$fa-var-address-card: \\f2bb;\n$fa-var-contact-card: \\f2bb;\n$fa-var-vcard: \\f2bb;\n$fa-var-scale-unbalanced-flip: \\f516;\n$fa-var-balance-scale-right: \\f516;\n$fa-var-subscript: \\f12c;\n$fa-var-diamond-turn-right: \\f5eb;\n$fa-var-directions: \\f5eb;\n$fa-var-burst: \\e4dc;\n$fa-var-house-laptop: \\e066;\n$fa-var-laptop-house: \\e066;\n$fa-var-face-tired: \\f5c8;\n$fa-var-tired: \\f5c8;\n$fa-var-money-bills: \\e1f3;\n$fa-var-smog: \\f75f;\n$fa-var-crutch: \\f7f7;\n$fa-var-cloud-arrow-up: \\f0ee;\n$fa-var-cloud-upload: \\f0ee;\n$fa-var-cloud-upload-alt: \\f0ee;\n$fa-var-palette: \\f53f;\n$fa-var-arrows-turn-right: \\e4c0;\n$fa-var-vest: \\e085;\n$fa-var-ferry: \\e4ea;\n$fa-var-arrows-down-to-people: \\e4b9;\n$fa-var-seedling: \\f4d8;\n$fa-var-sprout: \\f4d8;\n$fa-var-left-right: \\f337;\n$fa-var-arrows-alt-h: \\f337;\n$fa-var-boxes-packing: \\e4c7;\n$fa-var-circle-arrow-left: \\f0a8;\n$fa-var-arrow-circle-left: \\f0a8;\n$fa-var-group-arrows-rotate: \\e4f6;\n$fa-var-bowl-food: \\e4c6;\n$fa-var-candy-cane: \\f786;\n$fa-var-arrow-down-wide-short: \\f160;\n$fa-var-sort-amount-asc: \\f160;\n$fa-var-sort-amount-down: \\f160;\n$fa-var-cloud-bolt: \\f76c;\n$fa-var-thunderstorm: \\f76c;\n$fa-var-text-slash: \\f87d;\n$fa-var-remove-format: \\f87d;\n$fa-var-face-smile-wink: \\f4da;\n$fa-var-smile-wink: \\f4da;\n$fa-var-file-word: \\f1c2;\n$fa-var-file-powerpoint: \\f1c4;\n$fa-var-arrows-left-right: \\f07e;\n$fa-var-arrows-h: \\f07e;\n$fa-var-house-lock: \\e510;\n$fa-var-cloud-arrow-down: \\f0ed;\n$fa-var-cloud-download: \\f0ed;\n$fa-var-cloud-download-alt: \\f0ed;\n$fa-var-children: \\e4e1;\n$fa-var-chalkboard: \\f51b;\n$fa-var-blackboard: \\f51b;\n$fa-var-user-large-slash: \\f4fa;\n$fa-var-user-alt-slash: \\f4fa;\n$fa-var-envelope-open: \\f2b6;\n$fa-var-handshake-simple-slash: \\e05f;\n$fa-var-handshake-alt-slash: \\e05f;\n$fa-var-mattress-pillow: \\e525;\n$fa-var-guarani-sign: \\e19a;\n$fa-var-arrows-rotate: \\f021;\n$fa-var-refresh: \\f021;\n$fa-var-sync: \\f021;\n$fa-var-fire-extinguisher: \\f134;\n$fa-var-cruzeiro-sign: \\e152;\n$fa-var-greater-than-equal: \\f532;\n$fa-var-shield-halved: \\f3ed;\n$fa-var-shield-alt: \\f3ed;\n$fa-var-book-atlas: \\f558;\n$fa-var-atlas: \\f558;\n$fa-var-virus: \\e074;\n$fa-var-envelope-circle-check: \\e4e8;\n$fa-var-layer-group: \\f5fd;\n$fa-var-arrows-to-dot: \\e4be;\n$fa-var-archway: \\f557;\n$fa-var-heart-circle-check: \\e4fd;\n$fa-var-house-chimney-crack: \\f6f1;\n$fa-var-house-damage: \\f6f1;\n$fa-var-file-zipper: \\f1c6;\n$fa-var-file-archive: \\f1c6;\n$fa-var-square: \\f0c8;\n$fa-var-martini-glass-empty: \\f000;\n$fa-var-glass-martini: \\f000;\n$fa-var-couch: \\f4b8;\n$fa-var-cedi-sign: \\e0df;\n$fa-var-italic: \\f033;\n$fa-var-table-cells-column-lock: \\e678;\n$fa-var-church: \\f51d;\n$fa-var-comments-dollar: \\f653;\n$fa-var-democrat: \\f747;\n$fa-var-z: \\5a;\n$fa-var-person-skiing: \\f7c9;\n$fa-var-skiing: \\f7c9;\n$fa-var-road-lock: \\e567;\n$fa-var-a: \\41;\n$fa-var-temperature-arrow-down: \\e03f;\n$fa-var-temperature-down: \\e03f;\n$fa-var-feather-pointed: \\f56b;\n$fa-var-feather-alt: \\f56b;\n$fa-var-p: \\50;\n$fa-var-snowflake: \\f2dc;\n$fa-var-newspaper: \\f1ea;\n$fa-var-rectangle-ad: \\f641;\n$fa-var-ad: \\f641;\n$fa-var-circle-arrow-right: \\f0a9;\n$fa-var-arrow-circle-right: \\f0a9;\n$fa-var-filter-circle-xmark: \\e17b;\n$fa-var-locust: \\e520;\n$fa-var-sort: \\f0dc;\n$fa-var-unsorted: \\f0dc;\n$fa-var-list-ol: \\f0cb;\n$fa-var-list-1-2: \\f0cb;\n$fa-var-list-numeric: \\f0cb;\n$fa-var-person-dress-burst: \\e544;\n$fa-var-money-check-dollar: \\f53d;\n$fa-var-money-check-alt: \\f53d;\n$fa-var-vector-square: \\f5cb;\n$fa-var-bread-slice: \\f7ec;\n$fa-var-language: \\f1ab;\n$fa-var-face-kiss-wink-heart: \\f598;\n$fa-var-kiss-wink-heart: \\f598;\n$fa-var-filter: \\f0b0;\n$fa-var-question: \\3f;\n$fa-var-file-signature: \\f573;\n$fa-var-up-down-left-right: \\f0b2;\n$fa-var-arrows-alt: \\f0b2;\n$fa-var-house-chimney-user: \\e065;\n$fa-var-hand-holding-heart: \\f4be;\n$fa-var-puzzle-piece: \\f12e;\n$fa-var-money-check: \\f53c;\n$fa-var-star-half-stroke: \\f5c0;\n$fa-var-star-half-alt: \\f5c0;\n$fa-var-code: \\f121;\n$fa-var-whiskey-glass: \\f7a0;\n$fa-var-glass-whiskey: \\f7a0;\n$fa-var-building-circle-exclamation: \\e4d3;\n$fa-var-magnifying-glass-chart: \\e522;\n$fa-var-arrow-up-right-from-square: \\f08e;\n$fa-var-external-link: \\f08e;\n$fa-var-cubes-stacked: \\e4e6;\n$fa-var-won-sign: \\f159;\n$fa-var-krw: \\f159;\n$fa-var-won: \\f159;\n$fa-var-virus-covid: \\e4a8;\n$fa-var-austral-sign: \\e0a9;\n$fa-var-f: \\46;\n$fa-var-leaf: \\f06c;\n$fa-var-road: \\f018;\n$fa-var-taxi: \\f1ba;\n$fa-var-cab: \\f1ba;\n$fa-var-person-circle-plus: \\e541;\n$fa-var-chart-pie: \\f200;\n$fa-var-pie-chart: \\f200;\n$fa-var-bolt-lightning: \\e0b7;\n$fa-var-sack-xmark: \\e56a;\n$fa-var-file-excel: \\f1c3;\n$fa-var-file-contract: \\f56c;\n$fa-var-fish-fins: \\e4f2;\n$fa-var-building-flag: \\e4d5;\n$fa-var-face-grin-beam: \\f582;\n$fa-var-grin-beam: \\f582;\n$fa-var-object-ungroup: \\f248;\n$fa-var-poop: \\f619;\n$fa-var-location-pin: \\f041;\n$fa-var-map-marker: \\f041;\n$fa-var-kaaba: \\f66b;\n$fa-var-toilet-paper: \\f71e;\n$fa-var-helmet-safety: \\f807;\n$fa-var-hard-hat: \\f807;\n$fa-var-hat-hard: \\f807;\n$fa-var-eject: \\f052;\n$fa-var-circle-right: \\f35a;\n$fa-var-arrow-alt-circle-right: \\f35a;\n$fa-var-plane-circle-check: \\e555;\n$fa-var-face-rolling-eyes: \\f5a5;\n$fa-var-meh-rolling-eyes: \\f5a5;\n$fa-var-object-group: \\f247;\n$fa-var-chart-line: \\f201;\n$fa-var-line-chart: \\f201;\n$fa-var-mask-ventilator: \\e524;\n$fa-var-arrow-right: \\f061;\n$fa-var-signs-post: \\f277;\n$fa-var-map-signs: \\f277;\n$fa-var-cash-register: \\f788;\n$fa-var-person-circle-question: \\e542;\n$fa-var-h: \\48;\n$fa-var-tarp: \\e57b;\n$fa-var-screwdriver-wrench: \\f7d9;\n$fa-var-tools: \\f7d9;\n$fa-var-arrows-to-eye: \\e4bf;\n$fa-var-plug-circle-bolt: \\e55b;\n$fa-var-heart: \\f004;\n$fa-var-mars-and-venus: \\f224;\n$fa-var-house-user: \\e1b0;\n$fa-var-home-user: \\e1b0;\n$fa-var-dumpster-fire: \\f794;\n$fa-var-house-crack: \\e3b1;\n$fa-var-martini-glass-citrus: \\f561;\n$fa-var-cocktail: \\f561;\n$fa-var-face-surprise: \\f5c2;\n$fa-var-surprise: \\f5c2;\n$fa-var-bottle-water: \\e4c5;\n$fa-var-circle-pause: \\f28b;\n$fa-var-pause-circle: \\f28b;\n$fa-var-toilet-paper-slash: \\e072;\n$fa-var-apple-whole: \\f5d1;\n$fa-var-apple-alt: \\f5d1;\n$fa-var-kitchen-set: \\e51a;\n$fa-var-r: \\52;\n$fa-var-temperature-quarter: \\f2ca;\n$fa-var-temperature-1: \\f2ca;\n$fa-var-thermometer-1: \\f2ca;\n$fa-var-thermometer-quarter: \\f2ca;\n$fa-var-cube: \\f1b2;\n$fa-var-bitcoin-sign: \\e0b4;\n$fa-var-shield-dog: \\e573;\n$fa-var-solar-panel: \\f5ba;\n$fa-var-lock-open: \\f3c1;\n$fa-var-elevator: \\e16d;\n$fa-var-money-bill-transfer: \\e528;\n$fa-var-money-bill-trend-up: \\e529;\n$fa-var-house-flood-water-circle-arrow-right: \\e50f;\n$fa-var-square-poll-horizontal: \\f682;\n$fa-var-poll-h: \\f682;\n$fa-var-circle: \\f111;\n$fa-var-backward-fast: \\f049;\n$fa-var-fast-backward: \\f049;\n$fa-var-recycle: \\f1b8;\n$fa-var-user-astronaut: \\f4fb;\n$fa-var-plane-slash: \\e069;\n$fa-var-trademark: \\f25c;\n$fa-var-basketball: \\f434;\n$fa-var-basketball-ball: \\f434;\n$fa-var-satellite-dish: \\f7c0;\n$fa-var-circle-up: \\f35b;\n$fa-var-arrow-alt-circle-up: \\f35b;\n$fa-var-mobile-screen-button: \\f3cd;\n$fa-var-mobile-alt: \\f3cd;\n$fa-var-volume-high: \\f028;\n$fa-var-volume-up: \\f028;\n$fa-var-users-rays: \\e593;\n$fa-var-wallet: \\f555;\n$fa-var-clipboard-check: \\f46c;\n$fa-var-file-audio: \\f1c7;\n$fa-var-burger: \\f805;\n$fa-var-hamburger: \\f805;\n$fa-var-wrench: \\f0ad;\n$fa-var-bugs: \\e4d0;\n$fa-var-rupee-sign: \\f156;\n$fa-var-rupee: \\f156;\n$fa-var-file-image: \\f1c5;\n$fa-var-circle-question: \\f059;\n$fa-var-question-circle: \\f059;\n$fa-var-plane-departure: \\f5b0;\n$fa-var-handshake-slash: \\e060;\n$fa-var-book-bookmark: \\e0bb;\n$fa-var-code-branch: \\f126;\n$fa-var-hat-cowboy: \\f8c0;\n$fa-var-bridge: \\e4c8;\n$fa-var-phone-flip: \\f879;\n$fa-var-phone-alt: \\f879;\n$fa-var-truck-front: \\e2b7;\n$fa-var-cat: \\f6be;\n$fa-var-anchor-circle-exclamation: \\e4ab;\n$fa-var-truck-field: \\e58d;\n$fa-var-route: \\f4d7;\n$fa-var-clipboard-question: \\e4e3;\n$fa-var-panorama: \\e209;\n$fa-var-comment-medical: \\f7f5;\n$fa-var-teeth-open: \\f62f;\n$fa-var-file-circle-minus: \\e4ed;\n$fa-var-tags: \\f02c;\n$fa-var-wine-glass: \\f4e3;\n$fa-var-forward-fast: \\f050;\n$fa-var-fast-forward: \\f050;\n$fa-var-face-meh-blank: \\f5a4;\n$fa-var-meh-blank: \\f5a4;\n$fa-var-square-parking: \\f540;\n$fa-var-parking: \\f540;\n$fa-var-house-signal: \\e012;\n$fa-var-bars-progress: \\f828;\n$fa-var-tasks-alt: \\f828;\n$fa-var-faucet-drip: \\e006;\n$fa-var-cart-flatbed: \\f474;\n$fa-var-dolly-flatbed: \\f474;\n$fa-var-ban-smoking: \\f54d;\n$fa-var-smoking-ban: \\f54d;\n$fa-var-terminal: \\f120;\n$fa-var-mobile-button: \\f10b;\n$fa-var-house-medical-flag: \\e514;\n$fa-var-basket-shopping: \\f291;\n$fa-var-shopping-basket: \\f291;\n$fa-var-tape: \\f4db;\n$fa-var-bus-simple: \\f55e;\n$fa-var-bus-alt: \\f55e;\n$fa-var-eye: \\f06e;\n$fa-var-face-sad-cry: \\f5b3;\n$fa-var-sad-cry: \\f5b3;\n$fa-var-audio-description: \\f29e;\n$fa-var-person-military-to-person: \\e54c;\n$fa-var-file-shield: \\e4f0;\n$fa-var-user-slash: \\f506;\n$fa-var-pen: \\f304;\n$fa-var-tower-observation: \\e586;\n$fa-var-file-code: \\f1c9;\n$fa-var-signal: \\f012;\n$fa-var-signal-5: \\f012;\n$fa-var-signal-perfect: \\f012;\n$fa-var-bus: \\f207;\n$fa-var-heart-circle-xmark: \\e501;\n$fa-var-house-chimney: \\e3af;\n$fa-var-home-lg: \\e3af;\n$fa-var-window-maximize: \\f2d0;\n$fa-var-face-frown: \\f119;\n$fa-var-frown: \\f119;\n$fa-var-prescription: \\f5b1;\n$fa-var-shop: \\f54f;\n$fa-var-store-alt: \\f54f;\n$fa-var-floppy-disk: \\f0c7;\n$fa-var-save: \\f0c7;\n$fa-var-vihara: \\f6a7;\n$fa-var-scale-unbalanced: \\f515;\n$fa-var-balance-scale-left: \\f515;\n$fa-var-sort-up: \\f0de;\n$fa-var-sort-asc: \\f0de;\n$fa-var-comment-dots: \\f4ad;\n$fa-var-commenting: \\f4ad;\n$fa-var-plant-wilt: \\e5aa;\n$fa-var-diamond: \\f219;\n$fa-var-face-grin-squint: \\f585;\n$fa-var-grin-squint: \\f585;\n$fa-var-hand-holding-dollar: \\f4c0;\n$fa-var-hand-holding-usd: \\f4c0;\n$fa-var-chart-diagram: \\e695;\n$fa-var-bacterium: \\e05a;\n$fa-var-hand-pointer: \\f25a;\n$fa-var-drum-steelpan: \\f56a;\n$fa-var-hand-scissors: \\f257;\n$fa-var-hands-praying: \\f684;\n$fa-var-praying-hands: \\f684;\n$fa-var-arrow-rotate-right: \\f01e;\n$fa-var-arrow-right-rotate: \\f01e;\n$fa-var-arrow-rotate-forward: \\f01e;\n$fa-var-redo: \\f01e;\n$fa-var-biohazard: \\f780;\n$fa-var-location-crosshairs: \\f601;\n$fa-var-location: \\f601;\n$fa-var-mars-double: \\f227;\n$fa-var-child-dress: \\e59c;\n$fa-var-users-between-lines: \\e591;\n$fa-var-lungs-virus: \\e067;\n$fa-var-face-grin-tears: \\f588;\n$fa-var-grin-tears: \\f588;\n$fa-var-phone: \\f095;\n$fa-var-calendar-xmark: \\f273;\n$fa-var-calendar-times: \\f273;\n$fa-var-child-reaching: \\e59d;\n$fa-var-head-side-virus: \\e064;\n$fa-var-user-gear: \\f4fe;\n$fa-var-user-cog: \\f4fe;\n$fa-var-arrow-up-1-9: \\f163;\n$fa-var-sort-numeric-up: \\f163;\n$fa-var-door-closed: \\f52a;\n$fa-var-shield-virus: \\e06c;\n$fa-var-dice-six: \\f526;\n$fa-var-mosquito-net: \\e52c;\n$fa-var-file-fragment: \\e697;\n$fa-var-bridge-water: \\e4ce;\n$fa-var-person-booth: \\f756;\n$fa-var-text-width: \\f035;\n$fa-var-hat-wizard: \\f6e8;\n$fa-var-pen-fancy: \\f5ac;\n$fa-var-person-digging: \\f85e;\n$fa-var-digging: \\f85e;\n$fa-var-trash: \\f1f8;\n$fa-var-gauge-simple: \\f629;\n$fa-var-gauge-simple-med: \\f629;\n$fa-var-tachometer-average: \\f629;\n$fa-var-book-medical: \\f7e6;\n$fa-var-poo: \\f2fe;\n$fa-var-quote-right: \\f10e;\n$fa-var-quote-right-alt: \\f10e;\n$fa-var-shirt: \\f553;\n$fa-var-t-shirt: \\f553;\n$fa-var-tshirt: \\f553;\n$fa-var-cubes: \\f1b3;\n$fa-var-divide: \\f529;\n$fa-var-tenge-sign: \\f7d7;\n$fa-var-tenge: \\f7d7;\n$fa-var-headphones: \\f025;\n$fa-var-hands-holding: \\f4c2;\n$fa-var-hands-clapping: \\e1a8;\n$fa-var-republican: \\f75e;\n$fa-var-arrow-left: \\f060;\n$fa-var-person-circle-xmark: \\e543;\n$fa-var-ruler: \\f545;\n$fa-var-align-left: \\f036;\n$fa-var-dice-d6: \\f6d1;\n$fa-var-restroom: \\f7bd;\n$fa-var-j: \\4a;\n$fa-var-users-viewfinder: \\e595;\n$fa-var-file-video: \\f1c8;\n$fa-var-up-right-from-square: \\f35d;\n$fa-var-external-link-alt: \\f35d;\n$fa-var-table-cells: \\f00a;\n$fa-var-th: \\f00a;\n$fa-var-file-pdf: \\f1c1;\n$fa-var-book-bible: \\f647;\n$fa-var-bible: \\f647;\n$fa-var-o: \\4f;\n$fa-var-suitcase-medical: \\f0fa;\n$fa-var-medkit: \\f0fa;\n$fa-var-user-secret: \\f21b;\n$fa-var-otter: \\f700;\n$fa-var-person-dress: \\f182;\n$fa-var-female: \\f182;\n$fa-var-comment-dollar: \\f651;\n$fa-var-business-time: \\f64a;\n$fa-var-briefcase-clock: \\f64a;\n$fa-var-table-cells-large: \\f009;\n$fa-var-th-large: \\f009;\n$fa-var-book-tanakh: \\f827;\n$fa-var-tanakh: \\f827;\n$fa-var-phone-volume: \\f2a0;\n$fa-var-volume-control-phone: \\f2a0;\n$fa-var-hat-cowboy-side: \\f8c1;\n$fa-var-clipboard-user: \\f7f3;\n$fa-var-child: \\f1ae;\n$fa-var-lira-sign: \\f195;\n$fa-var-satellite: \\f7bf;\n$fa-var-plane-lock: \\e558;\n$fa-var-tag: \\f02b;\n$fa-var-comment: \\f075;\n$fa-var-cake-candles: \\f1fd;\n$fa-var-birthday-cake: \\f1fd;\n$fa-var-cake: \\f1fd;\n$fa-var-envelope: \\f0e0;\n$fa-var-angles-up: \\f102;\n$fa-var-angle-double-up: \\f102;\n$fa-var-paperclip: \\f0c6;\n$fa-var-arrow-right-to-city: \\e4b3;\n$fa-var-ribbon: \\f4d6;\n$fa-var-lungs: \\f604;\n$fa-var-arrow-up-9-1: \\f887;\n$fa-var-sort-numeric-up-alt: \\f887;\n$fa-var-litecoin-sign: \\e1d3;\n$fa-var-border-none: \\f850;\n$fa-var-circle-nodes: \\e4e2;\n$fa-var-parachute-box: \\f4cd;\n$fa-var-indent: \\f03c;\n$fa-var-truck-field-un: \\e58e;\n$fa-var-hourglass: \\f254;\n$fa-var-hourglass-empty: \\f254;\n$fa-var-mountain: \\f6fc;\n$fa-var-user-doctor: \\f0f0;\n$fa-var-user-md: \\f0f0;\n$fa-var-circle-info: \\f05a;\n$fa-var-info-circle: \\f05a;\n$fa-var-cloud-meatball: \\f73b;\n$fa-var-camera: \\f030;\n$fa-var-camera-alt: \\f030;\n$fa-var-square-virus: \\e578;\n$fa-var-meteor: \\f753;\n$fa-var-car-on: \\e4dd;\n$fa-var-sleigh: \\f7cc;\n$fa-var-arrow-down-1-9: \\f162;\n$fa-var-sort-numeric-asc: \\f162;\n$fa-var-sort-numeric-down: \\f162;\n$fa-var-hand-holding-droplet: \\f4c1;\n$fa-var-hand-holding-water: \\f4c1;\n$fa-var-water: \\f773;\n$fa-var-calendar-check: \\f274;\n$fa-var-braille: \\f2a1;\n$fa-var-prescription-bottle-medical: \\f486;\n$fa-var-prescription-bottle-alt: \\f486;\n$fa-var-landmark: \\f66f;\n$fa-var-truck: \\f0d1;\n$fa-var-crosshairs: \\f05b;\n$fa-var-person-cane: \\e53c;\n$fa-var-tent: \\e57d;\n$fa-var-vest-patches: \\e086;\n$fa-var-check-double: \\f560;\n$fa-var-arrow-down-a-z: \\f15d;\n$fa-var-sort-alpha-asc: \\f15d;\n$fa-var-sort-alpha-down: \\f15d;\n$fa-var-money-bill-wheat: \\e52a;\n$fa-var-cookie: \\f563;\n$fa-var-arrow-rotate-left: \\f0e2;\n$fa-var-arrow-left-rotate: \\f0e2;\n$fa-var-arrow-rotate-back: \\f0e2;\n$fa-var-arrow-rotate-backward: \\f0e2;\n$fa-var-undo: \\f0e2;\n$fa-var-hard-drive: \\f0a0;\n$fa-var-hdd: \\f0a0;\n$fa-var-face-grin-squint-tears: \\f586;\n$fa-var-grin-squint-tears: \\f586;\n$fa-var-dumbbell: \\f44b;\n$fa-var-rectangle-list: \\f022;\n$fa-var-list-alt: \\f022;\n$fa-var-tarp-droplet: \\e57c;\n$fa-var-house-medical-circle-check: \\e511;\n$fa-var-person-skiing-nordic: \\f7ca;\n$fa-var-skiing-nordic: \\f7ca;\n$fa-var-calendar-plus: \\f271;\n$fa-var-plane-arrival: \\f5af;\n$fa-var-circle-left: \\f359;\n$fa-var-arrow-alt-circle-left: \\f359;\n$fa-var-train-subway: \\f239;\n$fa-var-subway: \\f239;\n$fa-var-chart-gantt: \\e0e4;\n$fa-var-indian-rupee-sign: \\e1bc;\n$fa-var-indian-rupee: \\e1bc;\n$fa-var-inr: \\e1bc;\n$fa-var-crop-simple: \\f565;\n$fa-var-crop-alt: \\f565;\n$fa-var-money-bill-1: \\f3d1;\n$fa-var-money-bill-alt: \\f3d1;\n$fa-var-left-long: \\f30a;\n$fa-var-long-arrow-alt-left: \\f30a;\n$fa-var-dna: \\f471;\n$fa-var-virus-slash: \\e075;\n$fa-var-minus: \\f068;\n$fa-var-subtract: \\f068;\n$fa-var-chess: \\f439;\n$fa-var-arrow-left-long: \\f177;\n$fa-var-long-arrow-left: \\f177;\n$fa-var-plug-circle-check: \\e55c;\n$fa-var-street-view: \\f21d;\n$fa-var-franc-sign: \\e18f;\n$fa-var-volume-off: \\f026;\n$fa-var-hands-asl-interpreting: \\f2a3;\n$fa-var-american-sign-language-interpreting: \\f2a3;\n$fa-var-asl-interpreting: \\f2a3;\n$fa-var-hands-american-sign-language-interpreting: \\f2a3;\n$fa-var-gear: \\f013;\n$fa-var-cog: \\f013;\n$fa-var-droplet-slash: \\f5c7;\n$fa-var-tint-slash: \\f5c7;\n$fa-var-mosque: \\f678;\n$fa-var-mosquito: \\e52b;\n$fa-var-star-of-david: \\f69a;\n$fa-var-person-military-rifle: \\e54b;\n$fa-var-cart-shopping: \\f07a;\n$fa-var-shopping-cart: \\f07a;\n$fa-var-vials: \\f493;\n$fa-var-plug-circle-plus: \\e55f;\n$fa-var-place-of-worship: \\f67f;\n$fa-var-grip-vertical: \\f58e;\n$fa-var-hexagon-nodes: \\e699;\n$fa-var-arrow-turn-up: \\f148;\n$fa-var-level-up: \\f148;\n$fa-var-u: \\55;\n$fa-var-square-root-variable: \\f698;\n$fa-var-square-root-alt: \\f698;\n$fa-var-clock: \\f017;\n$fa-var-clock-four: \\f017;\n$fa-var-backward-step: \\f048;\n$fa-var-step-backward: \\f048;\n$fa-var-pallet: \\f482;\n$fa-var-faucet: \\e005;\n$fa-var-baseball-bat-ball: \\f432;\n$fa-var-s: \\53;\n$fa-var-timeline: \\e29c;\n$fa-var-keyboard: \\f11c;\n$fa-var-caret-down: \\f0d7;\n$fa-var-house-chimney-medical: \\f7f2;\n$fa-var-clinic-medical: \\f7f2;\n$fa-var-temperature-three-quarters: \\f2c8;\n$fa-var-temperature-3: \\f2c8;\n$fa-var-thermometer-3: \\f2c8;\n$fa-var-thermometer-three-quarters: \\f2c8;\n$fa-var-mobile-screen: \\f3cf;\n$fa-var-mobile-android-alt: \\f3cf;\n$fa-var-plane-up: \\e22d;\n$fa-var-piggy-bank: \\f4d3;\n$fa-var-battery-half: \\f242;\n$fa-var-battery-3: \\f242;\n$fa-var-mountain-city: \\e52e;\n$fa-var-coins: \\f51e;\n$fa-var-khanda: \\f66d;\n$fa-var-sliders: \\f1de;\n$fa-var-sliders-h: \\f1de;\n$fa-var-folder-tree: \\f802;\n$fa-var-network-wired: \\f6ff;\n$fa-var-map-pin: \\f276;\n$fa-var-hamsa: \\f665;\n$fa-var-cent-sign: \\e3f5;\n$fa-var-flask: \\f0c3;\n$fa-var-person-pregnant: \\e31e;\n$fa-var-wand-sparkles: \\f72b;\n$fa-var-ellipsis-vertical: \\f142;\n$fa-var-ellipsis-v: \\f142;\n$fa-var-ticket: \\f145;\n$fa-var-power-off: \\f011;\n$fa-var-right-long: \\f30b;\n$fa-var-long-arrow-alt-right: \\f30b;\n$fa-var-flag-usa: \\f74d;\n$fa-var-laptop-file: \\e51d;\n$fa-var-tty: \\f1e4;\n$fa-var-teletype: \\f1e4;\n$fa-var-diagram-next: \\e476;\n$fa-var-person-rifle: \\e54e;\n$fa-var-house-medical-circle-exclamation: \\e512;\n$fa-var-closed-captioning: \\f20a;\n$fa-var-person-hiking: \\f6ec;\n$fa-var-hiking: \\f6ec;\n$fa-var-venus-double: \\f226;\n$fa-var-images: \\f302;\n$fa-var-calculator: \\f1ec;\n$fa-var-people-pulling: \\e535;\n$fa-var-n: \\4e;\n$fa-var-cable-car: \\f7da;\n$fa-var-tram: \\f7da;\n$fa-var-cloud-rain: \\f73d;\n$fa-var-building-circle-xmark: \\e4d4;\n$fa-var-ship: \\f21a;\n$fa-var-arrows-down-to-line: \\e4b8;\n$fa-var-download: \\f019;\n$fa-var-face-grin: \\f580;\n$fa-var-grin: \\f580;\n$fa-var-delete-left: \\f55a;\n$fa-var-backspace: \\f55a;\n$fa-var-eye-dropper: \\f1fb;\n$fa-var-eye-dropper-empty: \\f1fb;\n$fa-var-eyedropper: \\f1fb;\n$fa-var-file-circle-check: \\e5a0;\n$fa-var-forward: \\f04e;\n$fa-var-mobile: \\f3ce;\n$fa-var-mobile-android: \\f3ce;\n$fa-var-mobile-phone: \\f3ce;\n$fa-var-face-meh: \\f11a;\n$fa-var-meh: \\f11a;\n$fa-var-align-center: \\f037;\n$fa-var-book-skull: \\f6b7;\n$fa-var-book-dead: \\f6b7;\n$fa-var-id-card: \\f2c2;\n$fa-var-drivers-license: \\f2c2;\n$fa-var-outdent: \\f03b;\n$fa-var-dedent: \\f03b;\n$fa-var-heart-circle-exclamation: \\e4fe;\n$fa-var-house: \\f015;\n$fa-var-home: \\f015;\n$fa-var-home-alt: \\f015;\n$fa-var-home-lg-alt: \\f015;\n$fa-var-calendar-week: \\f784;\n$fa-var-laptop-medical: \\f812;\n$fa-var-b: \\42;\n$fa-var-file-medical: \\f477;\n$fa-var-dice-one: \\f525;\n$fa-var-kiwi-bird: \\f535;\n$fa-var-arrow-right-arrow-left: \\f0ec;\n$fa-var-exchange: \\f0ec;\n$fa-var-rotate-right: \\f2f9;\n$fa-var-redo-alt: \\f2f9;\n$fa-var-rotate-forward: \\f2f9;\n$fa-var-utensils: \\f2e7;\n$fa-var-cutlery: \\f2e7;\n$fa-var-arrow-up-wide-short: \\f161;\n$fa-var-sort-amount-up: \\f161;\n$fa-var-mill-sign: \\e1ed;\n$fa-var-bowl-rice: \\e2eb;\n$fa-var-skull: \\f54c;\n$fa-var-tower-broadcast: \\f519;\n$fa-var-broadcast-tower: \\f519;\n$fa-var-truck-pickup: \\f63c;\n$fa-var-up-long: \\f30c;\n$fa-var-long-arrow-alt-up: \\f30c;\n$fa-var-stop: \\f04d;\n$fa-var-code-merge: \\f387;\n$fa-var-upload: \\f093;\n$fa-var-hurricane: \\f751;\n$fa-var-mound: \\e52d;\n$fa-var-toilet-portable: \\e583;\n$fa-var-compact-disc: \\f51f;\n$fa-var-file-arrow-down: \\f56d;\n$fa-var-file-download: \\f56d;\n$fa-var-caravan: \\f8ff;\n$fa-var-shield-cat: \\e572;\n$fa-var-bolt: \\f0e7;\n$fa-var-zap: \\f0e7;\n$fa-var-glass-water: \\e4f4;\n$fa-var-oil-well: \\e532;\n$fa-var-vault: \\e2c5;\n$fa-var-mars: \\f222;\n$fa-var-toilet: \\f7d8;\n$fa-var-plane-circle-xmark: \\e557;\n$fa-var-yen-sign: \\f157;\n$fa-var-cny: \\f157;\n$fa-var-jpy: \\f157;\n$fa-var-rmb: \\f157;\n$fa-var-yen: \\f157;\n$fa-var-ruble-sign: \\f158;\n$fa-var-rouble: \\f158;\n$fa-var-rub: \\f158;\n$fa-var-ruble: \\f158;\n$fa-var-sun: \\f185;\n$fa-var-guitar: \\f7a6;\n$fa-var-face-laugh-wink: \\f59c;\n$fa-var-laugh-wink: \\f59c;\n$fa-var-horse-head: \\f7ab;\n$fa-var-bore-hole: \\e4c3;\n$fa-var-industry: \\f275;\n$fa-var-circle-down: \\f358;\n$fa-var-arrow-alt-circle-down: \\f358;\n$fa-var-arrows-turn-to-dots: \\e4c1;\n$fa-var-florin-sign: \\e184;\n$fa-var-arrow-down-short-wide: \\f884;\n$fa-var-sort-amount-desc: \\f884;\n$fa-var-sort-amount-down-alt: \\f884;\n$fa-var-less-than: \\3c;\n$fa-var-angle-down: \\f107;\n$fa-var-car-tunnel: \\e4de;\n$fa-var-head-side-cough: \\e061;\n$fa-var-grip-lines: \\f7a4;\n$fa-var-thumbs-down: \\f165;\n$fa-var-user-lock: \\f502;\n$fa-var-arrow-right-long: \\f178;\n$fa-var-long-arrow-right: \\f178;\n$fa-var-anchor-circle-xmark: \\e4ac;\n$fa-var-ellipsis: \\f141;\n$fa-var-ellipsis-h: \\f141;\n$fa-var-chess-pawn: \\f443;\n$fa-var-kit-medical: \\f479;\n$fa-var-first-aid: \\f479;\n$fa-var-person-through-window: \\e5a9;\n$fa-var-toolbox: \\f552;\n$fa-var-hands-holding-circle: \\e4fb;\n$fa-var-bug: \\f188;\n$fa-var-credit-card: \\f09d;\n$fa-var-credit-card-alt: \\f09d;\n$fa-var-car: \\f1b9;\n$fa-var-automobile: \\f1b9;\n$fa-var-hand-holding-hand: \\e4f7;\n$fa-var-book-open-reader: \\f5da;\n$fa-var-book-reader: \\f5da;\n$fa-var-mountain-sun: \\e52f;\n$fa-var-arrows-left-right-to-line: \\e4ba;\n$fa-var-dice-d20: \\f6cf;\n$fa-var-truck-droplet: \\e58c;\n$fa-var-file-circle-xmark: \\e5a1;\n$fa-var-temperature-arrow-up: \\e040;\n$fa-var-temperature-up: \\e040;\n$fa-var-medal: \\f5a2;\n$fa-var-bed: \\f236;\n$fa-var-square-h: \\f0fd;\n$fa-var-h-square: \\f0fd;\n$fa-var-podcast: \\f2ce;\n$fa-var-temperature-full: \\f2c7;\n$fa-var-temperature-4: \\f2c7;\n$fa-var-thermometer-4: \\f2c7;\n$fa-var-thermometer-full: \\f2c7;\n$fa-var-bell: \\f0f3;\n$fa-var-superscript: \\f12b;\n$fa-var-plug-circle-xmark: \\e560;\n$fa-var-star-of-life: \\f621;\n$fa-var-phone-slash: \\f3dd;\n$fa-var-paint-roller: \\f5aa;\n$fa-var-handshake-angle: \\f4c4;\n$fa-var-hands-helping: \\f4c4;\n$fa-var-location-dot: \\f3c5;\n$fa-var-map-marker-alt: \\f3c5;\n$fa-var-file: \\f15b;\n$fa-var-greater-than: \\3e;\n$fa-var-person-swimming: \\f5c4;\n$fa-var-swimmer: \\f5c4;\n$fa-var-arrow-down: \\f063;\n$fa-var-droplet: \\f043;\n$fa-var-tint: \\f043;\n$fa-var-eraser: \\f12d;\n$fa-var-earth-americas: \\f57d;\n$fa-var-earth: \\f57d;\n$fa-var-earth-america: \\f57d;\n$fa-var-globe-americas: \\f57d;\n$fa-var-person-burst: \\e53b;\n$fa-var-dove: \\f4ba;\n$fa-var-battery-empty: \\f244;\n$fa-var-battery-0: \\f244;\n$fa-var-socks: \\f696;\n$fa-var-inbox: \\f01c;\n$fa-var-section: \\e447;\n$fa-var-gauge-high: \\f625;\n$fa-var-tachometer-alt: \\f625;\n$fa-var-tachometer-alt-fast: \\f625;\n$fa-var-envelope-open-text: \\f658;\n$fa-var-hospital: \\f0f8;\n$fa-var-hospital-alt: \\f0f8;\n$fa-var-hospital-wide: \\f0f8;\n$fa-var-wine-bottle: \\f72f;\n$fa-var-chess-rook: \\f447;\n$fa-var-bars-staggered: \\f550;\n$fa-var-reorder: \\f550;\n$fa-var-stream: \\f550;\n$fa-var-dharmachakra: \\f655;\n$fa-var-hotdog: \\f80f;\n$fa-var-person-walking-with-cane: \\f29d;\n$fa-var-blind: \\f29d;\n$fa-var-drum: \\f569;\n$fa-var-ice-cream: \\f810;\n$fa-var-heart-circle-bolt: \\e4fc;\n$fa-var-fax: \\f1ac;\n$fa-var-paragraph: \\f1dd;\n$fa-var-check-to-slot: \\f772;\n$fa-var-vote-yea: \\f772;\n$fa-var-star-half: \\f089;\n$fa-var-boxes-stacked: \\f468;\n$fa-var-boxes: \\f468;\n$fa-var-boxes-alt: \\f468;\n$fa-var-link: \\f0c1;\n$fa-var-chain: \\f0c1;\n$fa-var-ear-listen: \\f2a2;\n$fa-var-assistive-listening-systems: \\f2a2;\n$fa-var-tree-city: \\e587;\n$fa-var-play: \\f04b;\n$fa-var-font: \\f031;\n$fa-var-table-cells-row-lock: \\e67a;\n$fa-var-rupiah-sign: \\e23d;\n$fa-var-magnifying-glass: \\f002;\n$fa-var-search: \\f002;\n$fa-var-table-tennis-paddle-ball: \\f45d;\n$fa-var-ping-pong-paddle-ball: \\f45d;\n$fa-var-table-tennis: \\f45d;\n$fa-var-person-dots-from-line: \\f470;\n$fa-var-diagnoses: \\f470;\n$fa-var-trash-can-arrow-up: \\f82a;\n$fa-var-trash-restore-alt: \\f82a;\n$fa-var-naira-sign: \\e1f6;\n$fa-var-cart-arrow-down: \\f218;\n$fa-var-walkie-talkie: \\f8ef;\n$fa-var-file-pen: \\f31c;\n$fa-var-file-edit: \\f31c;\n$fa-var-receipt: \\f543;\n$fa-var-square-pen: \\f14b;\n$fa-var-pen-square: \\f14b;\n$fa-var-pencil-square: \\f14b;\n$fa-var-suitcase-rolling: \\f5c1;\n$fa-var-person-circle-exclamation: \\e53f;\n$fa-var-chevron-down: \\f078;\n$fa-var-battery-full: \\f240;\n$fa-var-battery: \\f240;\n$fa-var-battery-5: \\f240;\n$fa-var-skull-crossbones: \\f714;\n$fa-var-code-compare: \\e13a;\n$fa-var-list-ul: \\f0ca;\n$fa-var-list-dots: \\f0ca;\n$fa-var-school-lock: \\e56f;\n$fa-var-tower-cell: \\e585;\n$fa-var-down-long: \\f309;\n$fa-var-long-arrow-alt-down: \\f309;\n$fa-var-ranking-star: \\e561;\n$fa-var-chess-king: \\f43f;\n$fa-var-person-harassing: \\e549;\n$fa-var-brazilian-real-sign: \\e46c;\n$fa-var-landmark-dome: \\f752;\n$fa-var-landmark-alt: \\f752;\n$fa-var-arrow-up: \\f062;\n$fa-var-tv: \\f26c;\n$fa-var-television: \\f26c;\n$fa-var-tv-alt: \\f26c;\n$fa-var-shrimp: \\e448;\n$fa-var-list-check: \\f0ae;\n$fa-var-tasks: \\f0ae;\n$fa-var-jug-detergent: \\e519;\n$fa-var-circle-user: \\f2bd;\n$fa-var-user-circle: \\f2bd;\n$fa-var-user-shield: \\f505;\n$fa-var-wind: \\f72e;\n$fa-var-car-burst: \\f5e1;\n$fa-var-car-crash: \\f5e1;\n$fa-var-y: \\59;\n$fa-var-person-snowboarding: \\f7ce;\n$fa-var-snowboarding: \\f7ce;\n$fa-var-truck-fast: \\f48b;\n$fa-var-shipping-fast: \\f48b;\n$fa-var-fish: \\f578;\n$fa-var-user-graduate: \\f501;\n$fa-var-circle-half-stroke: \\f042;\n$fa-var-adjust: \\f042;\n$fa-var-clapperboard: \\e131;\n$fa-var-circle-radiation: \\f7ba;\n$fa-var-radiation-alt: \\f7ba;\n$fa-var-baseball: \\f433;\n$fa-var-baseball-ball: \\f433;\n$fa-var-jet-fighter-up: \\e518;\n$fa-var-diagram-project: \\f542;\n$fa-var-project-diagram: \\f542;\n$fa-var-copy: \\f0c5;\n$fa-var-volume-xmark: \\f6a9;\n$fa-var-volume-mute: \\f6a9;\n$fa-var-volume-times: \\f6a9;\n$fa-var-hand-sparkles: \\e05d;\n$fa-var-grip: \\f58d;\n$fa-var-grip-horizontal: \\f58d;\n$fa-var-share-from-square: \\f14d;\n$fa-var-share-square: \\f14d;\n$fa-var-child-combatant: \\e4e0;\n$fa-var-child-rifle: \\e4e0;\n$fa-var-gun: \\e19b;\n$fa-var-square-phone: \\f098;\n$fa-var-phone-square: \\f098;\n$fa-var-plus: \\2b;\n$fa-var-add: \\2b;\n$fa-var-expand: \\f065;\n$fa-var-computer: \\e4e5;\n$fa-var-xmark: \\f00d;\n$fa-var-close: \\f00d;\n$fa-var-multiply: \\f00d;\n$fa-var-remove: \\f00d;\n$fa-var-times: \\f00d;\n$fa-var-arrows-up-down-left-right: \\f047;\n$fa-var-arrows: \\f047;\n$fa-var-chalkboard-user: \\f51c;\n$fa-var-chalkboard-teacher: \\f51c;\n$fa-var-peso-sign: \\e222;\n$fa-var-building-shield: \\e4d8;\n$fa-var-baby: \\f77c;\n$fa-var-users-line: \\e592;\n$fa-var-quote-left: \\f10d;\n$fa-var-quote-left-alt: \\f10d;\n$fa-var-tractor: \\f722;\n$fa-var-trash-arrow-up: \\f829;\n$fa-var-trash-restore: \\f829;\n$fa-var-arrow-down-up-lock: \\e4b0;\n$fa-var-lines-leaning: \\e51e;\n$fa-var-ruler-combined: \\f546;\n$fa-var-copyright: \\f1f9;\n$fa-var-equals: \\3d;\n$fa-var-blender: \\f517;\n$fa-var-teeth: \\f62e;\n$fa-var-shekel-sign: \\f20b;\n$fa-var-ils: \\f20b;\n$fa-var-shekel: \\f20b;\n$fa-var-sheqel: \\f20b;\n$fa-var-sheqel-sign: \\f20b;\n$fa-var-map: \\f279;\n$fa-var-rocket: \\f135;\n$fa-var-photo-film: \\f87c;\n$fa-var-photo-video: \\f87c;\n$fa-var-folder-minus: \\f65d;\n$fa-var-hexagon-nodes-bolt: \\e69a;\n$fa-var-store: \\f54e;\n$fa-var-arrow-trend-up: \\e098;\n$fa-var-plug-circle-minus: \\e55e;\n$fa-var-sign-hanging: \\f4d9;\n$fa-var-sign: \\f4d9;\n$fa-var-bezier-curve: \\f55b;\n$fa-var-bell-slash: \\f1f6;\n$fa-var-tablet: \\f3fb;\n$fa-var-tablet-android: \\f3fb;\n$fa-var-school-flag: \\e56e;\n$fa-var-fill: \\f575;\n$fa-var-angle-up: \\f106;\n$fa-var-drumstick-bite: \\f6d7;\n$fa-var-holly-berry: \\f7aa;\n$fa-var-chevron-left: \\f053;\n$fa-var-bacteria: \\e059;\n$fa-var-hand-lizard: \\f258;\n$fa-var-notdef: \\e1fe;\n$fa-var-disease: \\f7fa;\n$fa-var-briefcase-medical: \\f469;\n$fa-var-genderless: \\f22d;\n$fa-var-chevron-right: \\f054;\n$fa-var-retweet: \\f079;\n$fa-var-car-rear: \\f5de;\n$fa-var-car-alt: \\f5de;\n$fa-var-pump-soap: \\e06b;\n$fa-var-video-slash: \\f4e2;\n$fa-var-battery-quarter: \\f243;\n$fa-var-battery-2: \\f243;\n$fa-var-radio: \\f8d7;\n$fa-var-baby-carriage: \\f77d;\n$fa-var-carriage-baby: \\f77d;\n$fa-var-traffic-light: \\f637;\n$fa-var-thermometer: \\f491;\n$fa-var-vr-cardboard: \\f729;\n$fa-var-hand-middle-finger: \\f806;\n$fa-var-percent: \\25;\n$fa-var-percentage: \\25;\n$fa-var-truck-moving: \\f4df;\n$fa-var-glass-water-droplet: \\e4f5;\n$fa-var-display: \\e163;\n$fa-var-face-smile: \\f118;\n$fa-var-smile: \\f118;\n$fa-var-thumbtack: \\f08d;\n$fa-var-thumb-tack: \\f08d;\n$fa-var-trophy: \\f091;\n$fa-var-person-praying: \\f683;\n$fa-var-pray: \\f683;\n$fa-var-hammer: \\f6e3;\n$fa-var-hand-peace: \\f25b;\n$fa-var-rotate: \\f2f1;\n$fa-var-sync-alt: \\f2f1;\n$fa-var-spinner: \\f110;\n$fa-var-robot: \\f544;\n$fa-var-peace: \\f67c;\n$fa-var-gears: \\f085;\n$fa-var-cogs: \\f085;\n$fa-var-warehouse: \\f494;\n$fa-var-arrow-up-right-dots: \\e4b7;\n$fa-var-splotch: \\f5bc;\n$fa-var-face-grin-hearts: \\f584;\n$fa-var-grin-hearts: \\f584;\n$fa-var-dice-four: \\f524;\n$fa-var-sim-card: \\f7c4;\n$fa-var-transgender: \\f225;\n$fa-var-transgender-alt: \\f225;\n$fa-var-mercury: \\f223;\n$fa-var-arrow-turn-down: \\f149;\n$fa-var-level-down: \\f149;\n$fa-var-person-falling-burst: \\e547;\n$fa-var-award: \\f559;\n$fa-var-ticket-simple: \\f3ff;\n$fa-var-ticket-alt: \\f3ff;\n$fa-var-building: \\f1ad;\n$fa-var-angles-left: \\f100;\n$fa-var-angle-double-left: \\f100;\n$fa-var-qrcode: \\f029;\n$fa-var-clock-rotate-left: \\f1da;\n$fa-var-history: \\f1da;\n$fa-var-face-grin-beam-sweat: \\f583;\n$fa-var-grin-beam-sweat: \\f583;\n$fa-var-file-export: \\f56e;\n$fa-var-arrow-right-from-file: \\f56e;\n$fa-var-shield: \\f132;\n$fa-var-shield-blank: \\f132;\n$fa-var-arrow-up-short-wide: \\f885;\n$fa-var-sort-amount-up-alt: \\f885;\n$fa-var-comment-nodes: \\e696;\n$fa-var-house-medical: \\e3b2;\n$fa-var-golf-ball-tee: \\f450;\n$fa-var-golf-ball: \\f450;\n$fa-var-circle-chevron-left: \\f137;\n$fa-var-chevron-circle-left: \\f137;\n$fa-var-house-chimney-window: \\e00d;\n$fa-var-pen-nib: \\f5ad;\n$fa-var-tent-arrow-turn-left: \\e580;\n$fa-var-tents: \\e582;\n$fa-var-wand-magic: \\f0d0;\n$fa-var-magic: \\f0d0;\n$fa-var-dog: \\f6d3;\n$fa-var-carrot: \\f787;\n$fa-var-moon: \\f186;\n$fa-var-wine-glass-empty: \\f5ce;\n$fa-var-wine-glass-alt: \\f5ce;\n$fa-var-cheese: \\f7ef;\n$fa-var-yin-yang: \\f6ad;\n$fa-var-music: \\f001;\n$fa-var-code-commit: \\f386;\n$fa-var-temperature-low: \\f76b;\n$fa-var-person-biking: \\f84a;\n$fa-var-biking: \\f84a;\n$fa-var-broom: \\f51a;\n$fa-var-shield-heart: \\e574;\n$fa-var-gopuram: \\f664;\n$fa-var-earth-oceania: \\e47b;\n$fa-var-globe-oceania: \\e47b;\n$fa-var-square-xmark: \\f2d3;\n$fa-var-times-square: \\f2d3;\n$fa-var-xmark-square: \\f2d3;\n$fa-var-hashtag: \\23;\n$fa-var-up-right-and-down-left-from-center: \\f424;\n$fa-var-expand-alt: \\f424;\n$fa-var-oil-can: \\f613;\n$fa-var-t: \\54;\n$fa-var-hippo: \\f6ed;\n$fa-var-chart-column: \\e0e3;\n$fa-var-infinity: \\f534;\n$fa-var-vial-circle-check: \\e596;\n$fa-var-person-arrow-down-to-line: \\e538;\n$fa-var-voicemail: \\f897;\n$fa-var-fan: \\f863;\n$fa-var-person-walking-luggage: \\e554;\n$fa-var-up-down: \\f338;\n$fa-var-arrows-alt-v: \\f338;\n$fa-var-cloud-moon-rain: \\f73c;\n$fa-var-calendar: \\f133;\n$fa-var-trailer: \\e041;\n$fa-var-bahai: \\f666;\n$fa-var-haykal: \\f666;\n$fa-var-sd-card: \\f7c2;\n$fa-var-dragon: \\f6d5;\n$fa-var-shoe-prints: \\f54b;\n$fa-var-circle-plus: \\f055;\n$fa-var-plus-circle: \\f055;\n$fa-var-face-grin-tongue-wink: \\f58b;\n$fa-var-grin-tongue-wink: \\f58b;\n$fa-var-hand-holding: \\f4bd;\n$fa-var-plug-circle-exclamation: \\e55d;\n$fa-var-link-slash: \\f127;\n$fa-var-chain-broken: \\f127;\n$fa-var-chain-slash: \\f127;\n$fa-var-unlink: \\f127;\n$fa-var-clone: \\f24d;\n$fa-var-person-walking-arrow-loop-left: \\e551;\n$fa-var-arrow-up-z-a: \\f882;\n$fa-var-sort-alpha-up-alt: \\f882;\n$fa-var-fire-flame-curved: \\f7e4;\n$fa-var-fire-alt: \\f7e4;\n$fa-var-tornado: \\f76f;\n$fa-var-file-circle-plus: \\e494;\n$fa-var-book-quran: \\f687;\n$fa-var-quran: \\f687;\n$fa-var-anchor: \\f13d;\n$fa-var-border-all: \\f84c;\n$fa-var-face-angry: \\f556;\n$fa-var-angry: \\f556;\n$fa-var-cookie-bite: \\f564;\n$fa-var-arrow-trend-down: \\e097;\n$fa-var-rss: \\f09e;\n$fa-var-feed: \\f09e;\n$fa-var-draw-polygon: \\f5ee;\n$fa-var-scale-balanced: \\f24e;\n$fa-var-balance-scale: \\f24e;\n$fa-var-gauge-simple-high: \\f62a;\n$fa-var-tachometer: \\f62a;\n$fa-var-tachometer-fast: \\f62a;\n$fa-var-shower: \\f2cc;\n$fa-var-desktop: \\f390;\n$fa-var-desktop-alt: \\f390;\n$fa-var-m: \\4d;\n$fa-var-table-list: \\f00b;\n$fa-var-th-list: \\f00b;\n$fa-var-comment-sms: \\f7cd;\n$fa-var-sms: \\f7cd;\n$fa-var-book: \\f02d;\n$fa-var-user-plus: \\f234;\n$fa-var-check: \\f00c;\n$fa-var-battery-three-quarters: \\f241;\n$fa-var-battery-4: \\f241;\n$fa-var-house-circle-check: \\e509;\n$fa-var-angle-left: \\f104;\n$fa-var-diagram-successor: \\e47a;\n$fa-var-truck-arrow-right: \\e58b;\n$fa-var-arrows-split-up-and-left: \\e4bc;\n$fa-var-hand-fist: \\f6de;\n$fa-var-fist-raised: \\f6de;\n$fa-var-cloud-moon: \\f6c3;\n$fa-var-briefcase: \\f0b1;\n$fa-var-person-falling: \\e546;\n$fa-var-image-portrait: \\f3e0;\n$fa-var-portrait: \\f3e0;\n$fa-var-user-tag: \\f507;\n$fa-var-rug: \\e569;\n$fa-var-earth-europe: \\f7a2;\n$fa-var-globe-europe: \\f7a2;\n$fa-var-cart-flatbed-suitcase: \\f59d;\n$fa-var-luggage-cart: \\f59d;\n$fa-var-rectangle-xmark: \\f410;\n$fa-var-rectangle-times: \\f410;\n$fa-var-times-rectangle: \\f410;\n$fa-var-window-close: \\f410;\n$fa-var-baht-sign: \\e0ac;\n$fa-var-book-open: \\f518;\n$fa-var-book-journal-whills: \\f66a;\n$fa-var-journal-whills: \\f66a;\n$fa-var-handcuffs: \\e4f8;\n$fa-var-triangle-exclamation: \\f071;\n$fa-var-exclamation-triangle: \\f071;\n$fa-var-warning: \\f071;\n$fa-var-database: \\f1c0;\n$fa-var-share: \\f064;\n$fa-var-mail-forward: \\f064;\n$fa-var-bottle-droplet: \\e4c4;\n$fa-var-mask-face: \\e1d7;\n$fa-var-hill-rockslide: \\e508;\n$fa-var-right-left: \\f362;\n$fa-var-exchange-alt: \\f362;\n$fa-var-paper-plane: \\f1d8;\n$fa-var-road-circle-exclamation: \\e565;\n$fa-var-dungeon: \\f6d9;\n$fa-var-align-right: \\f038;\n$fa-var-money-bill-1-wave: \\f53b;\n$fa-var-money-bill-wave-alt: \\f53b;\n$fa-var-life-ring: \\f1cd;\n$fa-var-hands: \\f2a7;\n$fa-var-sign-language: \\f2a7;\n$fa-var-signing: \\f2a7;\n$fa-var-calendar-day: \\f783;\n$fa-var-water-ladder: \\f5c5;\n$fa-var-ladder-water: \\f5c5;\n$fa-var-swimming-pool: \\f5c5;\n$fa-var-arrows-up-down: \\f07d;\n$fa-var-arrows-v: \\f07d;\n$fa-var-face-grimace: \\f57f;\n$fa-var-grimace: \\f57f;\n$fa-var-wheelchair-move: \\e2ce;\n$fa-var-wheelchair-alt: \\e2ce;\n$fa-var-turn-down: \\f3be;\n$fa-var-level-down-alt: \\f3be;\n$fa-var-person-walking-arrow-right: \\e552;\n$fa-var-square-envelope: \\f199;\n$fa-var-envelope-square: \\f199;\n$fa-var-dice: \\f522;\n$fa-var-bowling-ball: \\f436;\n$fa-var-brain: \\f5dc;\n$fa-var-bandage: \\f462;\n$fa-var-band-aid: \\f462;\n$fa-var-calendar-minus: \\f272;\n$fa-var-circle-xmark: \\f057;\n$fa-var-times-circle: \\f057;\n$fa-var-xmark-circle: \\f057;\n$fa-var-gifts: \\f79c;\n$fa-var-hotel: \\f594;\n$fa-var-earth-asia: \\f57e;\n$fa-var-globe-asia: \\f57e;\n$fa-var-id-card-clip: \\f47f;\n$fa-var-id-card-alt: \\f47f;\n$fa-var-magnifying-glass-plus: \\f00e;\n$fa-var-search-plus: \\f00e;\n$fa-var-thumbs-up: \\f164;\n$fa-var-user-clock: \\f4fd;\n$fa-var-hand-dots: \\f461;\n$fa-var-allergies: \\f461;\n$fa-var-file-invoice: \\f570;\n$fa-var-window-minimize: \\f2d1;\n$fa-var-mug-saucer: \\f0f4;\n$fa-var-coffee: \\f0f4;\n$fa-var-brush: \\f55d;\n$fa-var-file-half-dashed: \\e698;\n$fa-var-mask: \\f6fa;\n$fa-var-magnifying-glass-minus: \\f010;\n$fa-var-search-minus: \\f010;\n$fa-var-ruler-vertical: \\f548;\n$fa-var-user-large: \\f406;\n$fa-var-user-alt: \\f406;\n$fa-var-train-tram: \\e5b4;\n$fa-var-user-nurse: \\f82f;\n$fa-var-syringe: \\f48e;\n$fa-var-cloud-sun: \\f6c4;\n$fa-var-stopwatch-20: \\e06f;\n$fa-var-square-full: \\f45c;\n$fa-var-magnet: \\f076;\n$fa-var-jar: \\e516;\n$fa-var-note-sticky: \\f249;\n$fa-var-sticky-note: \\f249;\n$fa-var-bug-slash: \\e490;\n$fa-var-arrow-up-from-water-pump: \\e4b6;\n$fa-var-bone: \\f5d7;\n$fa-var-table-cells-row-unlock: \\e691;\n$fa-var-user-injured: \\f728;\n$fa-var-face-sad-tear: \\f5b4;\n$fa-var-sad-tear: \\f5b4;\n$fa-var-plane: \\f072;\n$fa-var-tent-arrows-down: \\e581;\n$fa-var-exclamation: \\21;\n$fa-var-arrows-spin: \\e4bb;\n$fa-var-print: \\f02f;\n$fa-var-turkish-lira-sign: \\e2bb;\n$fa-var-try: \\e2bb;\n$fa-var-turkish-lira: \\e2bb;\n$fa-var-dollar-sign: \\24;\n$fa-var-dollar: \\24;\n$fa-var-usd: \\24;\n$fa-var-x: \\58;\n$fa-var-magnifying-glass-dollar: \\f688;\n$fa-var-search-dollar: \\f688;\n$fa-var-users-gear: \\f509;\n$fa-var-users-cog: \\f509;\n$fa-var-person-military-pointing: \\e54a;\n$fa-var-building-columns: \\f19c;\n$fa-var-bank: \\f19c;\n$fa-var-institution: \\f19c;\n$fa-var-museum: \\f19c;\n$fa-var-university: \\f19c;\n$fa-var-umbrella: \\f0e9;\n$fa-var-trowel: \\e589;\n$fa-var-d: \\44;\n$fa-var-stapler: \\e5af;\n$fa-var-masks-theater: \\f630;\n$fa-var-theater-masks: \\f630;\n$fa-var-kip-sign: \\e1c4;\n$fa-var-hand-point-left: \\f0a5;\n$fa-var-handshake-simple: \\f4c6;\n$fa-var-handshake-alt: \\f4c6;\n$fa-var-jet-fighter: \\f0fb;\n$fa-var-fighter-jet: \\f0fb;\n$fa-var-square-share-nodes: \\f1e1;\n$fa-var-share-alt-square: \\f1e1;\n$fa-var-barcode: \\f02a;\n$fa-var-plus-minus: \\e43c;\n$fa-var-video: \\f03d;\n$fa-var-video-camera: \\f03d;\n$fa-var-graduation-cap: \\f19d;\n$fa-var-mortar-board: \\f19d;\n$fa-var-hand-holding-medical: \\e05c;\n$fa-var-person-circle-check: \\e53e;\n$fa-var-turn-up: \\f3bf;\n$fa-var-level-up-alt: \\f3bf;\n\n$fa-var-monero: \\f3d0;\n$fa-var-hooli: \\f427;\n$fa-var-yelp: \\f1e9;\n$fa-var-cc-visa: \\f1f0;\n$fa-var-lastfm: \\f202;\n$fa-var-shopware: \\f5b5;\n$fa-var-creative-commons-nc: \\f4e8;\n$fa-var-aws: \\f375;\n$fa-var-redhat: \\f7bc;\n$fa-var-yoast: \\f2b1;\n$fa-var-cloudflare: \\e07d;\n$fa-var-ups: \\f7e0;\n$fa-var-pixiv: \\e640;\n$fa-var-wpexplorer: \\f2de;\n$fa-var-dyalog: \\f399;\n$fa-var-bity: \\f37a;\n$fa-var-stackpath: \\f842;\n$fa-var-buysellads: \\f20d;\n$fa-var-first-order: \\f2b0;\n$fa-var-modx: \\f285;\n$fa-var-guilded: \\e07e;\n$fa-var-vnv: \\f40b;\n$fa-var-square-js: \\f3b9;\n$fa-var-js-square: \\f3b9;\n$fa-var-microsoft: \\f3ca;\n$fa-var-qq: \\f1d6;\n$fa-var-orcid: \\f8d2;\n$fa-var-java: \\f4e4;\n$fa-var-invision: \\f7b0;\n$fa-var-creative-commons-pd-alt: \\f4ed;\n$fa-var-centercode: \\f380;\n$fa-var-glide-g: \\f2a6;\n$fa-var-drupal: \\f1a9;\n$fa-var-jxl: \\e67b;\n$fa-var-dart-lang: \\e693;\n$fa-var-hire-a-helper: \\f3b0;\n$fa-var-creative-commons-by: \\f4e7;\n$fa-var-unity: \\e049;\n$fa-var-whmcs: \\f40d;\n$fa-var-rocketchat: \\f3e8;\n$fa-var-vk: \\f189;\n$fa-var-untappd: \\f405;\n$fa-var-mailchimp: \\f59e;\n$fa-var-css3-alt: \\f38b;\n$fa-var-square-reddit: \\f1a2;\n$fa-var-reddit-square: \\f1a2;\n$fa-var-vimeo-v: \\f27d;\n$fa-var-contao: \\f26d;\n$fa-var-square-font-awesome: \\e5ad;\n$fa-var-deskpro: \\f38f;\n$fa-var-brave: \\e63c;\n$fa-var-sistrix: \\f3ee;\n$fa-var-square-instagram: \\e055;\n$fa-var-instagram-square: \\e055;\n$fa-var-battle-net: \\f835;\n$fa-var-the-red-yeti: \\f69d;\n$fa-var-square-hacker-news: \\f3af;\n$fa-var-hacker-news-square: \\f3af;\n$fa-var-edge: \\f282;\n$fa-var-threads: \\e618;\n$fa-var-napster: \\f3d2;\n$fa-var-square-snapchat: \\f2ad;\n$fa-var-snapchat-square: \\f2ad;\n$fa-var-google-plus-g: \\f0d5;\n$fa-var-artstation: \\f77a;\n$fa-var-markdown: \\f60f;\n$fa-var-sourcetree: \\f7d3;\n$fa-var-google-plus: \\f2b3;\n$fa-var-diaspora: \\f791;\n$fa-var-foursquare: \\f180;\n$fa-var-stack-overflow: \\f16c;\n$fa-var-github-alt: \\f113;\n$fa-var-phoenix-squadron: \\f511;\n$fa-var-pagelines: \\f18c;\n$fa-var-algolia: \\f36c;\n$fa-var-red-river: \\f3e3;\n$fa-var-creative-commons-sa: \\f4ef;\n$fa-var-safari: \\f267;\n$fa-var-google: \\f1a0;\n$fa-var-square-font-awesome-stroke: \\f35c;\n$fa-var-font-awesome-alt: \\f35c;\n$fa-var-atlassian: \\f77b;\n$fa-var-linkedin-in: \\f0e1;\n$fa-var-digital-ocean: \\f391;\n$fa-var-nimblr: \\f5a8;\n$fa-var-chromecast: \\f838;\n$fa-var-evernote: \\f839;\n$fa-var-hacker-news: \\f1d4;\n$fa-var-creative-commons-sampling: \\f4f0;\n$fa-var-adversal: \\f36a;\n$fa-var-creative-commons: \\f25e;\n$fa-var-watchman-monitoring: \\e087;\n$fa-var-fonticons: \\f280;\n$fa-var-weixin: \\f1d7;\n$fa-var-shirtsinbulk: \\f214;\n$fa-var-codepen: \\f1cb;\n$fa-var-git-alt: \\f841;\n$fa-var-lyft: \\f3c3;\n$fa-var-rev: \\f5b2;\n$fa-var-windows: \\f17a;\n$fa-var-wizards-of-the-coast: \\f730;\n$fa-var-square-viadeo: \\f2aa;\n$fa-var-viadeo-square: \\f2aa;\n$fa-var-meetup: \\f2e0;\n$fa-var-centos: \\f789;\n$fa-var-adn: \\f170;\n$fa-var-cloudsmith: \\f384;\n$fa-var-opensuse: \\e62b;\n$fa-var-pied-piper-alt: \\f1a8;\n$fa-var-square-dribbble: \\f397;\n$fa-var-dribbble-square: \\f397;\n$fa-var-codiepie: \\f284;\n$fa-var-node: \\f419;\n$fa-var-mix: \\f3cb;\n$fa-var-steam: \\f1b6;\n$fa-var-cc-apple-pay: \\f416;\n$fa-var-scribd: \\f28a;\n$fa-var-debian: \\e60b;\n$fa-var-openid: \\f19b;\n$fa-var-instalod: \\e081;\n$fa-var-files-pinwheel: \\e69f;\n$fa-var-expeditedssl: \\f23e;\n$fa-var-sellcast: \\f2da;\n$fa-var-square-twitter: \\f081;\n$fa-var-twitter-square: \\f081;\n$fa-var-r-project: \\f4f7;\n$fa-var-delicious: \\f1a5;\n$fa-var-freebsd: \\f3a4;\n$fa-var-vuejs: \\f41f;\n$fa-var-accusoft: \\f369;\n$fa-var-ioxhost: \\f208;\n$fa-var-fonticons-fi: \\f3a2;\n$fa-var-app-store: \\f36f;\n$fa-var-cc-mastercard: \\f1f1;\n$fa-var-itunes-note: \\f3b5;\n$fa-var-golang: \\e40f;\n$fa-var-kickstarter: \\f3bb;\n$fa-var-square-kickstarter: \\f3bb;\n$fa-var-grav: \\f2d6;\n$fa-var-weibo: \\f18a;\n$fa-var-uncharted: \\e084;\n$fa-var-firstdraft: \\f3a1;\n$fa-var-square-youtube: \\f431;\n$fa-var-youtube-square: \\f431;\n$fa-var-wikipedia-w: \\f266;\n$fa-var-wpressr: \\f3e4;\n$fa-var-rendact: \\f3e4;\n$fa-var-angellist: \\f209;\n$fa-var-galactic-republic: \\f50c;\n$fa-var-nfc-directional: \\e530;\n$fa-var-skype: \\f17e;\n$fa-var-joget: \\f3b7;\n$fa-var-fedora: \\f798;\n$fa-var-stripe-s: \\f42a;\n$fa-var-meta: \\e49b;\n$fa-var-laravel: \\f3bd;\n$fa-var-hotjar: \\f3b1;\n$fa-var-bluetooth-b: \\f294;\n$fa-var-square-letterboxd: \\e62e;\n$fa-var-sticker-mule: \\f3f7;\n$fa-var-creative-commons-zero: \\f4f3;\n$fa-var-hips: \\f452;\n$fa-var-css: \\e6a2;\n$fa-var-behance: \\f1b4;\n$fa-var-reddit: \\f1a1;\n$fa-var-discord: \\f392;\n$fa-var-chrome: \\f268;\n$fa-var-app-store-ios: \\f370;\n$fa-var-cc-discover: \\f1f2;\n$fa-var-wpbeginner: \\f297;\n$fa-var-confluence: \\f78d;\n$fa-var-shoelace: \\e60c;\n$fa-var-mdb: \\f8ca;\n$fa-var-dochub: \\f394;\n$fa-var-accessible-icon: \\f368;\n$fa-var-ebay: \\f4f4;\n$fa-var-amazon: \\f270;\n$fa-var-unsplash: \\e07c;\n$fa-var-yarn: \\f7e3;\n$fa-var-square-steam: \\f1b7;\n$fa-var-steam-square: \\f1b7;\n$fa-var-500px: \\f26e;\n$fa-var-square-vimeo: \\f194;\n$fa-var-vimeo-square: \\f194;\n$fa-var-asymmetrik: \\f372;\n$fa-var-font-awesome: \\f2b4;\n$fa-var-font-awesome-flag: \\f2b4;\n$fa-var-font-awesome-logo-full: \\f2b4;\n$fa-var-gratipay: \\f184;\n$fa-var-apple: \\f179;\n$fa-var-hive: \\e07f;\n$fa-var-gitkraken: \\f3a6;\n$fa-var-keybase: \\f4f5;\n$fa-var-apple-pay: \\f415;\n$fa-var-padlet: \\e4a0;\n$fa-var-amazon-pay: \\f42c;\n$fa-var-square-github: \\f092;\n$fa-var-github-square: \\f092;\n$fa-var-stumbleupon: \\f1a4;\n$fa-var-fedex: \\f797;\n$fa-var-phoenix-framework: \\f3dc;\n$fa-var-shopify: \\e057;\n$fa-var-neos: \\f612;\n$fa-var-square-threads: \\e619;\n$fa-var-hackerrank: \\f5f7;\n$fa-var-researchgate: \\f4f8;\n$fa-var-swift: \\f8e1;\n$fa-var-angular: \\f420;\n$fa-var-speakap: \\f3f3;\n$fa-var-angrycreative: \\f36e;\n$fa-var-y-combinator: \\f23b;\n$fa-var-empire: \\f1d1;\n$fa-var-envira: \\f299;\n$fa-var-google-scholar: \\e63b;\n$fa-var-square-gitlab: \\e5ae;\n$fa-var-gitlab-square: \\e5ae;\n$fa-var-studiovinari: \\f3f8;\n$fa-var-pied-piper: \\f2ae;\n$fa-var-wordpress: \\f19a;\n$fa-var-product-hunt: \\f288;\n$fa-var-firefox: \\f269;\n$fa-var-linode: \\f2b8;\n$fa-var-goodreads: \\f3a8;\n$fa-var-square-odnoklassniki: \\f264;\n$fa-var-odnoklassniki-square: \\f264;\n$fa-var-jsfiddle: \\f1cc;\n$fa-var-sith: \\f512;\n$fa-var-themeisle: \\f2b2;\n$fa-var-page4: \\f3d7;\n$fa-var-hashnode: \\e499;\n$fa-var-react: \\f41b;\n$fa-var-cc-paypal: \\f1f4;\n$fa-var-squarespace: \\f5be;\n$fa-var-cc-stripe: \\f1f5;\n$fa-var-creative-commons-share: \\f4f2;\n$fa-var-bitcoin: \\f379;\n$fa-var-keycdn: \\f3ba;\n$fa-var-opera: \\f26a;\n$fa-var-itch-io: \\f83a;\n$fa-var-umbraco: \\f8e8;\n$fa-var-galactic-senate: \\f50d;\n$fa-var-ubuntu: \\f7df;\n$fa-var-draft2digital: \\f396;\n$fa-var-stripe: \\f429;\n$fa-var-houzz: \\f27c;\n$fa-var-gg: \\f260;\n$fa-var-dhl: \\f790;\n$fa-var-square-pinterest: \\f0d3;\n$fa-var-pinterest-square: \\f0d3;\n$fa-var-xing: \\f168;\n$fa-var-blackberry: \\f37b;\n$fa-var-creative-commons-pd: \\f4ec;\n$fa-var-playstation: \\f3df;\n$fa-var-quinscape: \\f459;\n$fa-var-less: \\f41d;\n$fa-var-blogger-b: \\f37d;\n$fa-var-opencart: \\f23d;\n$fa-var-vine: \\f1ca;\n$fa-var-signal-messenger: \\e663;\n$fa-var-paypal: \\f1ed;\n$fa-var-gitlab: \\f296;\n$fa-var-typo3: \\f42b;\n$fa-var-reddit-alien: \\f281;\n$fa-var-yahoo: \\f19e;\n$fa-var-dailymotion: \\e052;\n$fa-var-affiliatetheme: \\f36b;\n$fa-var-pied-piper-pp: \\f1a7;\n$fa-var-bootstrap: \\f836;\n$fa-var-odnoklassniki: \\f263;\n$fa-var-nfc-symbol: \\e531;\n$fa-var-mintbit: \\e62f;\n$fa-var-ethereum: \\f42e;\n$fa-var-speaker-deck: \\f83c;\n$fa-var-creative-commons-nc-eu: \\f4e9;\n$fa-var-patreon: \\f3d9;\n$fa-var-avianex: \\f374;\n$fa-var-ello: \\f5f1;\n$fa-var-gofore: \\f3a7;\n$fa-var-bimobject: \\f378;\n$fa-var-brave-reverse: \\e63d;\n$fa-var-facebook-f: \\f39e;\n$fa-var-square-google-plus: \\f0d4;\n$fa-var-google-plus-square: \\f0d4;\n$fa-var-web-awesome: \\e682;\n$fa-var-mandalorian: \\f50f;\n$fa-var-first-order-alt: \\f50a;\n$fa-var-osi: \\f41a;\n$fa-var-google-wallet: \\f1ee;\n$fa-var-d-and-d-beyond: \\f6ca;\n$fa-var-periscope: \\f3da;\n$fa-var-fulcrum: \\f50b;\n$fa-var-cloudscale: \\f383;\n$fa-var-forumbee: \\f211;\n$fa-var-mizuni: \\f3cc;\n$fa-var-schlix: \\f3ea;\n$fa-var-square-xing: \\f169;\n$fa-var-xing-square: \\f169;\n$fa-var-bandcamp: \\f2d5;\n$fa-var-wpforms: \\f298;\n$fa-var-cloudversify: \\f385;\n$fa-var-usps: \\f7e1;\n$fa-var-megaport: \\f5a3;\n$fa-var-magento: \\f3c4;\n$fa-var-spotify: \\f1bc;\n$fa-var-optin-monster: \\f23c;\n$fa-var-fly: \\f417;\n$fa-var-square-bluesky: \\e6a3;\n$fa-var-aviato: \\f421;\n$fa-var-itunes: \\f3b4;\n$fa-var-cuttlefish: \\f38c;\n$fa-var-blogger: \\f37c;\n$fa-var-flickr: \\f16e;\n$fa-var-viber: \\f409;\n$fa-var-soundcloud: \\f1be;\n$fa-var-digg: \\f1a6;\n$fa-var-tencent-weibo: \\f1d5;\n$fa-var-letterboxd: \\e62d;\n$fa-var-symfony: \\f83d;\n$fa-var-maxcdn: \\f136;\n$fa-var-etsy: \\f2d7;\n$fa-var-facebook-messenger: \\f39f;\n$fa-var-audible: \\f373;\n$fa-var-think-peaks: \\f731;\n$fa-var-bilibili: \\e3d9;\n$fa-var-erlang: \\f39d;\n$fa-var-x-twitter: \\e61b;\n$fa-var-cotton-bureau: \\f89e;\n$fa-var-dashcube: \\f210;\n$fa-var-42-group: \\e080;\n$fa-var-innosoft: \\e080;\n$fa-var-stack-exchange: \\f18d;\n$fa-var-elementor: \\f430;\n$fa-var-square-pied-piper: \\e01e;\n$fa-var-pied-piper-square: \\e01e;\n$fa-var-creative-commons-nd: \\f4eb;\n$fa-var-palfed: \\f3d8;\n$fa-var-superpowers: \\f2dd;\n$fa-var-resolving: \\f3e7;\n$fa-var-xbox: \\f412;\n$fa-var-square-web-awesome-stroke: \\e684;\n$fa-var-searchengin: \\f3eb;\n$fa-var-tiktok: \\e07b;\n$fa-var-square-facebook: \\f082;\n$fa-var-facebook-square: \\f082;\n$fa-var-renren: \\f18b;\n$fa-var-linux: \\f17c;\n$fa-var-glide: \\f2a5;\n$fa-var-linkedin: \\f08c;\n$fa-var-hubspot: \\f3b2;\n$fa-var-deploydog: \\f38e;\n$fa-var-twitch: \\f1e8;\n$fa-var-flutter: \\e694;\n$fa-var-ravelry: \\f2d9;\n$fa-var-mixer: \\e056;\n$fa-var-square-lastfm: \\f203;\n$fa-var-lastfm-square: \\f203;\n$fa-var-vimeo: \\f40a;\n$fa-var-mendeley: \\f7b3;\n$fa-var-uniregistry: \\f404;\n$fa-var-figma: \\f799;\n$fa-var-creative-commons-remix: \\f4ee;\n$fa-var-cc-amazon-pay: \\f42d;\n$fa-var-dropbox: \\f16b;\n$fa-var-instagram: \\f16d;\n$fa-var-cmplid: \\e360;\n$fa-var-upwork: \\e641;\n$fa-var-facebook: \\f09a;\n$fa-var-gripfire: \\f3ac;\n$fa-var-jedi-order: \\f50e;\n$fa-var-uikit: \\f403;\n$fa-var-fort-awesome-alt: \\f3a3;\n$fa-var-phabricator: \\f3db;\n$fa-var-ussunnah: \\f407;\n$fa-var-earlybirds: \\f39a;\n$fa-var-trade-federation: \\f513;\n$fa-var-autoprefixer: \\f41c;\n$fa-var-whatsapp: \\f232;\n$fa-var-square-upwork: \\e67c;\n$fa-var-slideshare: \\f1e7;\n$fa-var-google-play: \\f3ab;\n$fa-var-viadeo: \\f2a9;\n$fa-var-line: \\f3c0;\n$fa-var-google-drive: \\f3aa;\n$fa-var-servicestack: \\f3ec;\n$fa-var-simplybuilt: \\f215;\n$fa-var-bitbucket: \\f171;\n$fa-var-imdb: \\f2d8;\n$fa-var-deezer: \\e077;\n$fa-var-raspberry-pi: \\f7bb;\n$fa-var-jira: \\f7b1;\n$fa-var-docker: \\f395;\n$fa-var-screenpal: \\e570;\n$fa-var-bluetooth: \\f293;\n$fa-var-gitter: \\f426;\n$fa-var-d-and-d: \\f38d;\n$fa-var-microblog: \\e01a;\n$fa-var-cc-diners-club: \\f24c;\n$fa-var-gg-circle: \\f261;\n$fa-var-pied-piper-hat: \\f4e5;\n$fa-var-kickstarter-k: \\f3bc;\n$fa-var-yandex: \\f413;\n$fa-var-readme: \\f4d5;\n$fa-var-html5: \\f13b;\n$fa-var-sellsy: \\f213;\n$fa-var-square-web-awesome: \\e683;\n$fa-var-sass: \\f41e;\n$fa-var-wirsindhandwerk: \\e2d0;\n$fa-var-wsh: \\e2d0;\n$fa-var-buromobelexperte: \\f37f;\n$fa-var-salesforce: \\f83b;\n$fa-var-octopus-deploy: \\e082;\n$fa-var-medapps: \\f3c6;\n$fa-var-ns8: \\f3d5;\n$fa-var-pinterest-p: \\f231;\n$fa-var-apper: \\f371;\n$fa-var-fort-awesome: \\f286;\n$fa-var-waze: \\f83f;\n$fa-var-bluesky: \\e671;\n$fa-var-cc-jcb: \\f24b;\n$fa-var-snapchat: \\f2ab;\n$fa-var-snapchat-ghost: \\f2ab;\n$fa-var-fantasy-flight-games: \\f6dc;\n$fa-var-rust: \\e07a;\n$fa-var-wix: \\f5cf;\n$fa-var-square-behance: \\f1b5;\n$fa-var-behance-square: \\f1b5;\n$fa-var-supple: \\f3f9;\n$fa-var-webflow: \\e65c;\n$fa-var-rebel: \\f1d0;\n$fa-var-css3: \\f13c;\n$fa-var-staylinked: \\f3f5;\n$fa-var-kaggle: \\f5fa;\n$fa-var-space-awesome: \\e5ac;\n$fa-var-deviantart: \\f1bd;\n$fa-var-cpanel: \\f388;\n$fa-var-goodreads-g: \\f3a9;\n$fa-var-square-git: \\f1d2;\n$fa-var-git-square: \\f1d2;\n$fa-var-square-tumblr: \\f174;\n$fa-var-tumblr-square: \\f174;\n$fa-var-trello: \\f181;\n$fa-var-creative-commons-nc-jp: \\f4ea;\n$fa-var-get-pocket: \\f265;\n$fa-var-perbyte: \\e083;\n$fa-var-grunt: \\f3ad;\n$fa-var-weebly: \\f5cc;\n$fa-var-connectdevelop: \\f20e;\n$fa-var-leanpub: \\f212;\n$fa-var-black-tie: \\f27e;\n$fa-var-themeco: \\f5c6;\n$fa-var-python: \\f3e2;\n$fa-var-android: \\f17b;\n$fa-var-bots: \\e340;\n$fa-var-free-code-camp: \\f2c5;\n$fa-var-hornbill: \\f592;\n$fa-var-js: \\f3b8;\n$fa-var-ideal: \\e013;\n$fa-var-git: \\f1d3;\n$fa-var-dev: \\f6cc;\n$fa-var-sketch: \\f7c6;\n$fa-var-yandex-international: \\f414;\n$fa-var-cc-amex: \\f1f3;\n$fa-var-uber: \\f402;\n$fa-var-github: \\f09b;\n$fa-var-php: \\f457;\n$fa-var-alipay: \\f642;\n$fa-var-youtube: \\f167;\n$fa-var-skyatlas: \\f216;\n$fa-var-firefox-browser: \\e007;\n$fa-var-replyd: \\f3e6;\n$fa-var-suse: \\f7d6;\n$fa-var-jenkins: \\f3b6;\n$fa-var-twitter: \\f099;\n$fa-var-rockrms: \\f3e9;\n$fa-var-pinterest: \\f0d2;\n$fa-var-buffer: \\f837;\n$fa-var-npm: \\f3d4;\n$fa-var-yammer: \\f840;\n$fa-var-btc: \\f15a;\n$fa-var-dribbble: \\f17d;\n$fa-var-stumbleupon-circle: \\f1a3;\n$fa-var-internet-explorer: \\f26b;\n$fa-var-stubber: \\e5c7;\n$fa-var-telegram: \\f2c6;\n$fa-var-telegram-plane: \\f2c6;\n$fa-var-old-republic: \\f510;\n$fa-var-odysee: \\e5c6;\n$fa-var-square-whatsapp: \\f40c;\n$fa-var-whatsapp-square: \\f40c;\n$fa-var-node-js: \\f3d3;\n$fa-var-edge-legacy: \\e078;\n$fa-var-slack: \\f198;\n$fa-var-slack-hash: \\f198;\n$fa-var-medrt: \\f3c8;\n$fa-var-usb: \\f287;\n$fa-var-tumblr: \\f173;\n$fa-var-vaadin: \\f408;\n$fa-var-quora: \\f2c4;\n$fa-var-square-x-twitter: \\e61a;\n$fa-var-reacteurope: \\f75d;\n$fa-var-medium: \\f23a;\n$fa-var-medium-m: \\f23a;\n$fa-var-amilia: \\f36d;\n$fa-var-mixcloud: \\f289;\n$fa-var-flipboard: \\f44d;\n$fa-var-viacoin: \\f237;\n$fa-var-critical-role: \\f6c9;\n$fa-var-sitrox: \\e44a;\n$fa-var-discourse: \\f393;\n$fa-var-joomla: \\f1aa;\n$fa-var-mastodon: \\f4f6;\n$fa-var-airbnb: \\f834;\n$fa-var-wolf-pack-battalion: \\f514;\n$fa-var-buy-n-large: \\f8a6;\n$fa-var-gulp: \\f3ae;\n$fa-var-creative-commons-sampling-plus: \\f4f1;\n$fa-var-strava: \\f428;\n$fa-var-ember: \\f423;\n$fa-var-canadian-maple-leaf: \\f785;\n$fa-var-teamspeak: \\f4f9;\n$fa-var-pushed: \\f3e1;\n$fa-var-wordpress-simple: \\f411;\n$fa-var-nutritionix: \\f3d6;\n$fa-var-wodu: \\e088;\n$fa-var-google-pay: \\e079;\n$fa-var-intercom: \\f7af;\n$fa-var-zhihu: \\f63f;\n$fa-var-korvue: \\f42f;\n$fa-var-pix: \\e43a;\n$fa-var-steam-symbol: \\f3f6;\n\n$fa-icons: (\n \"0\": $fa-var-0,\n \"1\": $fa-var-1,\n \"2\": $fa-var-2,\n \"3\": $fa-var-3,\n \"4\": $fa-var-4,\n \"5\": $fa-var-5,\n \"6\": $fa-var-6,\n \"7\": $fa-var-7,\n \"8\": $fa-var-8,\n \"9\": $fa-var-9,\n \"fill-drip\": $fa-var-fill-drip,\n \"arrows-to-circle\": $fa-var-arrows-to-circle,\n \"circle-chevron-right\": $fa-var-circle-chevron-right,\n \"chevron-circle-right\": $fa-var-chevron-circle-right,\n \"at\": $fa-var-at,\n \"trash-can\": $fa-var-trash-can,\n \"trash-alt\": $fa-var-trash-alt,\n \"text-height\": $fa-var-text-height,\n \"user-xmark\": $fa-var-user-xmark,\n \"user-times\": $fa-var-user-times,\n \"stethoscope\": $fa-var-stethoscope,\n \"message\": $fa-var-message,\n \"comment-alt\": $fa-var-comment-alt,\n \"info\": $fa-var-info,\n \"down-left-and-up-right-to-center\": $fa-var-down-left-and-up-right-to-center,\n \"compress-alt\": $fa-var-compress-alt,\n \"explosion\": $fa-var-explosion,\n \"file-lines\": $fa-var-file-lines,\n \"file-alt\": $fa-var-file-alt,\n \"file-text\": $fa-var-file-text,\n \"wave-square\": $fa-var-wave-square,\n \"ring\": $fa-var-ring,\n \"building-un\": $fa-var-building-un,\n \"dice-three\": $fa-var-dice-three,\n \"calendar-days\": $fa-var-calendar-days,\n \"calendar-alt\": $fa-var-calendar-alt,\n \"anchor-circle-check\": $fa-var-anchor-circle-check,\n \"building-circle-arrow-right\": $fa-var-building-circle-arrow-right,\n \"volleyball\": $fa-var-volleyball,\n \"volleyball-ball\": $fa-var-volleyball-ball,\n \"arrows-up-to-line\": $fa-var-arrows-up-to-line,\n \"sort-down\": $fa-var-sort-down,\n \"sort-desc\": $fa-var-sort-desc,\n \"circle-minus\": $fa-var-circle-minus,\n \"minus-circle\": $fa-var-minus-circle,\n \"door-open\": $fa-var-door-open,\n \"right-from-bracket\": $fa-var-right-from-bracket,\n \"sign-out-alt\": $fa-var-sign-out-alt,\n \"atom\": $fa-var-atom,\n \"soap\": $fa-var-soap,\n \"icons\": $fa-var-icons,\n \"heart-music-camera-bolt\": $fa-var-heart-music-camera-bolt,\n \"microphone-lines-slash\": $fa-var-microphone-lines-slash,\n \"microphone-alt-slash\": $fa-var-microphone-alt-slash,\n \"bridge-circle-check\": $fa-var-bridge-circle-check,\n \"pump-medical\": $fa-var-pump-medical,\n \"fingerprint\": $fa-var-fingerprint,\n \"hand-point-right\": $fa-var-hand-point-right,\n \"magnifying-glass-location\": $fa-var-magnifying-glass-location,\n \"search-location\": $fa-var-search-location,\n \"forward-step\": $fa-var-forward-step,\n \"step-forward\": $fa-var-step-forward,\n \"face-smile-beam\": $fa-var-face-smile-beam,\n \"smile-beam\": $fa-var-smile-beam,\n \"flag-checkered\": $fa-var-flag-checkered,\n \"football\": $fa-var-football,\n \"football-ball\": $fa-var-football-ball,\n \"school-circle-exclamation\": $fa-var-school-circle-exclamation,\n \"crop\": $fa-var-crop,\n \"angles-down\": $fa-var-angles-down,\n \"angle-double-down\": $fa-var-angle-double-down,\n \"users-rectangle\": $fa-var-users-rectangle,\n \"people-roof\": $fa-var-people-roof,\n \"people-line\": $fa-var-people-line,\n \"beer-mug-empty\": $fa-var-beer-mug-empty,\n \"beer\": $fa-var-beer,\n \"diagram-predecessor\": $fa-var-diagram-predecessor,\n \"arrow-up-long\": $fa-var-arrow-up-long,\n \"long-arrow-up\": $fa-var-long-arrow-up,\n \"fire-flame-simple\": $fa-var-fire-flame-simple,\n \"burn\": $fa-var-burn,\n \"person\": $fa-var-person,\n \"male\": $fa-var-male,\n \"laptop\": $fa-var-laptop,\n \"file-csv\": $fa-var-file-csv,\n \"menorah\": $fa-var-menorah,\n \"truck-plane\": $fa-var-truck-plane,\n \"record-vinyl\": $fa-var-record-vinyl,\n \"face-grin-stars\": $fa-var-face-grin-stars,\n \"grin-stars\": $fa-var-grin-stars,\n \"bong\": $fa-var-bong,\n \"spaghetti-monster-flying\": $fa-var-spaghetti-monster-flying,\n \"pastafarianism\": $fa-var-pastafarianism,\n \"arrow-down-up-across-line\": $fa-var-arrow-down-up-across-line,\n \"spoon\": $fa-var-spoon,\n \"utensil-spoon\": $fa-var-utensil-spoon,\n \"jar-wheat\": $fa-var-jar-wheat,\n \"envelopes-bulk\": $fa-var-envelopes-bulk,\n \"mail-bulk\": $fa-var-mail-bulk,\n \"file-circle-exclamation\": $fa-var-file-circle-exclamation,\n \"circle-h\": $fa-var-circle-h,\n \"hospital-symbol\": $fa-var-hospital-symbol,\n \"pager\": $fa-var-pager,\n \"address-book\": $fa-var-address-book,\n \"contact-book\": $fa-var-contact-book,\n \"strikethrough\": $fa-var-strikethrough,\n \"k\": $fa-var-k,\n \"landmark-flag\": $fa-var-landmark-flag,\n \"pencil\": $fa-var-pencil,\n \"pencil-alt\": $fa-var-pencil-alt,\n \"backward\": $fa-var-backward,\n \"caret-right\": $fa-var-caret-right,\n \"comments\": $fa-var-comments,\n \"paste\": $fa-var-paste,\n \"file-clipboard\": $fa-var-file-clipboard,\n \"code-pull-request\": $fa-var-code-pull-request,\n \"clipboard-list\": $fa-var-clipboard-list,\n \"truck-ramp-box\": $fa-var-truck-ramp-box,\n \"truck-loading\": $fa-var-truck-loading,\n \"user-check\": $fa-var-user-check,\n \"vial-virus\": $fa-var-vial-virus,\n \"sheet-plastic\": $fa-var-sheet-plastic,\n \"blog\": $fa-var-blog,\n \"user-ninja\": $fa-var-user-ninja,\n \"person-arrow-up-from-line\": $fa-var-person-arrow-up-from-line,\n \"scroll-torah\": $fa-var-scroll-torah,\n \"torah\": $fa-var-torah,\n \"broom-ball\": $fa-var-broom-ball,\n \"quidditch\": $fa-var-quidditch,\n \"quidditch-broom-ball\": $fa-var-quidditch-broom-ball,\n \"toggle-off\": $fa-var-toggle-off,\n \"box-archive\": $fa-var-box-archive,\n \"archive\": $fa-var-archive,\n \"person-drowning\": $fa-var-person-drowning,\n \"arrow-down-9-1\": $fa-var-arrow-down-9-1,\n \"sort-numeric-desc\": $fa-var-sort-numeric-desc,\n \"sort-numeric-down-alt\": $fa-var-sort-numeric-down-alt,\n \"face-grin-tongue-squint\": $fa-var-face-grin-tongue-squint,\n \"grin-tongue-squint\": $fa-var-grin-tongue-squint,\n \"spray-can\": $fa-var-spray-can,\n \"truck-monster\": $fa-var-truck-monster,\n \"w\": $fa-var-w,\n \"earth-africa\": $fa-var-earth-africa,\n \"globe-africa\": $fa-var-globe-africa,\n \"rainbow\": $fa-var-rainbow,\n \"circle-notch\": $fa-var-circle-notch,\n \"tablet-screen-button\": $fa-var-tablet-screen-button,\n \"tablet-alt\": $fa-var-tablet-alt,\n \"paw\": $fa-var-paw,\n \"cloud\": $fa-var-cloud,\n \"trowel-bricks\": $fa-var-trowel-bricks,\n \"face-flushed\": $fa-var-face-flushed,\n \"flushed\": $fa-var-flushed,\n \"hospital-user\": $fa-var-hospital-user,\n \"tent-arrow-left-right\": $fa-var-tent-arrow-left-right,\n \"gavel\": $fa-var-gavel,\n \"legal\": $fa-var-legal,\n \"binoculars\": $fa-var-binoculars,\n \"microphone-slash\": $fa-var-microphone-slash,\n \"box-tissue\": $fa-var-box-tissue,\n \"motorcycle\": $fa-var-motorcycle,\n \"bell-concierge\": $fa-var-bell-concierge,\n \"concierge-bell\": $fa-var-concierge-bell,\n \"pen-ruler\": $fa-var-pen-ruler,\n \"pencil-ruler\": $fa-var-pencil-ruler,\n \"people-arrows\": $fa-var-people-arrows,\n \"people-arrows-left-right\": $fa-var-people-arrows-left-right,\n \"mars-and-venus-burst\": $fa-var-mars-and-venus-burst,\n \"square-caret-right\": $fa-var-square-caret-right,\n \"caret-square-right\": $fa-var-caret-square-right,\n \"scissors\": $fa-var-scissors,\n \"cut\": $fa-var-cut,\n \"sun-plant-wilt\": $fa-var-sun-plant-wilt,\n \"toilets-portable\": $fa-var-toilets-portable,\n \"hockey-puck\": $fa-var-hockey-puck,\n \"table\": $fa-var-table,\n \"magnifying-glass-arrow-right\": $fa-var-magnifying-glass-arrow-right,\n \"tachograph-digital\": $fa-var-tachograph-digital,\n \"digital-tachograph\": $fa-var-digital-tachograph,\n \"users-slash\": $fa-var-users-slash,\n \"clover\": $fa-var-clover,\n \"reply\": $fa-var-reply,\n \"mail-reply\": $fa-var-mail-reply,\n \"star-and-crescent\": $fa-var-star-and-crescent,\n \"house-fire\": $fa-var-house-fire,\n \"square-minus\": $fa-var-square-minus,\n \"minus-square\": $fa-var-minus-square,\n \"helicopter\": $fa-var-helicopter,\n \"compass\": $fa-var-compass,\n \"square-caret-down\": $fa-var-square-caret-down,\n \"caret-square-down\": $fa-var-caret-square-down,\n \"file-circle-question\": $fa-var-file-circle-question,\n \"laptop-code\": $fa-var-laptop-code,\n \"swatchbook\": $fa-var-swatchbook,\n \"prescription-bottle\": $fa-var-prescription-bottle,\n \"bars\": $fa-var-bars,\n \"navicon\": $fa-var-navicon,\n \"people-group\": $fa-var-people-group,\n \"hourglass-end\": $fa-var-hourglass-end,\n \"hourglass-3\": $fa-var-hourglass-3,\n \"heart-crack\": $fa-var-heart-crack,\n \"heart-broken\": $fa-var-heart-broken,\n \"square-up-right\": $fa-var-square-up-right,\n \"external-link-square-alt\": $fa-var-external-link-square-alt,\n \"face-kiss-beam\": $fa-var-face-kiss-beam,\n \"kiss-beam\": $fa-var-kiss-beam,\n \"film\": $fa-var-film,\n \"ruler-horizontal\": $fa-var-ruler-horizontal,\n \"people-robbery\": $fa-var-people-robbery,\n \"lightbulb\": $fa-var-lightbulb,\n \"caret-left\": $fa-var-caret-left,\n \"circle-exclamation\": $fa-var-circle-exclamation,\n \"exclamation-circle\": $fa-var-exclamation-circle,\n \"school-circle-xmark\": $fa-var-school-circle-xmark,\n \"arrow-right-from-bracket\": $fa-var-arrow-right-from-bracket,\n \"sign-out\": $fa-var-sign-out,\n \"circle-chevron-down\": $fa-var-circle-chevron-down,\n \"chevron-circle-down\": $fa-var-chevron-circle-down,\n \"unlock-keyhole\": $fa-var-unlock-keyhole,\n \"unlock-alt\": $fa-var-unlock-alt,\n \"cloud-showers-heavy\": $fa-var-cloud-showers-heavy,\n \"headphones-simple\": $fa-var-headphones-simple,\n \"headphones-alt\": $fa-var-headphones-alt,\n \"sitemap\": $fa-var-sitemap,\n \"circle-dollar-to-slot\": $fa-var-circle-dollar-to-slot,\n \"donate\": $fa-var-donate,\n \"memory\": $fa-var-memory,\n \"road-spikes\": $fa-var-road-spikes,\n \"fire-burner\": $fa-var-fire-burner,\n \"flag\": $fa-var-flag,\n \"hanukiah\": $fa-var-hanukiah,\n \"feather\": $fa-var-feather,\n \"volume-low\": $fa-var-volume-low,\n \"volume-down\": $fa-var-volume-down,\n \"comment-slash\": $fa-var-comment-slash,\n \"cloud-sun-rain\": $fa-var-cloud-sun-rain,\n \"compress\": $fa-var-compress,\n \"wheat-awn\": $fa-var-wheat-awn,\n \"wheat-alt\": $fa-var-wheat-alt,\n \"ankh\": $fa-var-ankh,\n \"hands-holding-child\": $fa-var-hands-holding-child,\n \"asterisk\": $fa-var-asterisk,\n \"square-check\": $fa-var-square-check,\n \"check-square\": $fa-var-check-square,\n \"peseta-sign\": $fa-var-peseta-sign,\n \"heading\": $fa-var-heading,\n \"header\": $fa-var-header,\n \"ghost\": $fa-var-ghost,\n \"list\": $fa-var-list,\n \"list-squares\": $fa-var-list-squares,\n \"square-phone-flip\": $fa-var-square-phone-flip,\n \"phone-square-alt\": $fa-var-phone-square-alt,\n \"cart-plus\": $fa-var-cart-plus,\n \"gamepad\": $fa-var-gamepad,\n \"circle-dot\": $fa-var-circle-dot,\n \"dot-circle\": $fa-var-dot-circle,\n \"face-dizzy\": $fa-var-face-dizzy,\n \"dizzy\": $fa-var-dizzy,\n \"egg\": $fa-var-egg,\n \"house-medical-circle-xmark\": $fa-var-house-medical-circle-xmark,\n \"campground\": $fa-var-campground,\n \"folder-plus\": $fa-var-folder-plus,\n \"futbol\": $fa-var-futbol,\n \"futbol-ball\": $fa-var-futbol-ball,\n \"soccer-ball\": $fa-var-soccer-ball,\n \"paintbrush\": $fa-var-paintbrush,\n \"paint-brush\": $fa-var-paint-brush,\n \"lock\": $fa-var-lock,\n \"gas-pump\": $fa-var-gas-pump,\n \"hot-tub-person\": $fa-var-hot-tub-person,\n \"hot-tub\": $fa-var-hot-tub,\n \"map-location\": $fa-var-map-location,\n \"map-marked\": $fa-var-map-marked,\n \"house-flood-water\": $fa-var-house-flood-water,\n \"tree\": $fa-var-tree,\n \"bridge-lock\": $fa-var-bridge-lock,\n \"sack-dollar\": $fa-var-sack-dollar,\n \"pen-to-square\": $fa-var-pen-to-square,\n \"edit\": $fa-var-edit,\n \"car-side\": $fa-var-car-side,\n \"share-nodes\": $fa-var-share-nodes,\n \"share-alt\": $fa-var-share-alt,\n \"heart-circle-minus\": $fa-var-heart-circle-minus,\n \"hourglass-half\": $fa-var-hourglass-half,\n \"hourglass-2\": $fa-var-hourglass-2,\n \"microscope\": $fa-var-microscope,\n \"sink\": $fa-var-sink,\n \"bag-shopping\": $fa-var-bag-shopping,\n \"shopping-bag\": $fa-var-shopping-bag,\n \"arrow-down-z-a\": $fa-var-arrow-down-z-a,\n \"sort-alpha-desc\": $fa-var-sort-alpha-desc,\n \"sort-alpha-down-alt\": $fa-var-sort-alpha-down-alt,\n \"mitten\": $fa-var-mitten,\n \"person-rays\": $fa-var-person-rays,\n \"users\": $fa-var-users,\n \"eye-slash\": $fa-var-eye-slash,\n \"flask-vial\": $fa-var-flask-vial,\n \"hand\": $fa-var-hand,\n \"hand-paper\": $fa-var-hand-paper,\n \"om\": $fa-var-om,\n \"worm\": $fa-var-worm,\n \"house-circle-xmark\": $fa-var-house-circle-xmark,\n \"plug\": $fa-var-plug,\n \"chevron-up\": $fa-var-chevron-up,\n \"hand-spock\": $fa-var-hand-spock,\n \"stopwatch\": $fa-var-stopwatch,\n \"face-kiss\": $fa-var-face-kiss,\n \"kiss\": $fa-var-kiss,\n \"bridge-circle-xmark\": $fa-var-bridge-circle-xmark,\n \"face-grin-tongue\": $fa-var-face-grin-tongue,\n \"grin-tongue\": $fa-var-grin-tongue,\n \"chess-bishop\": $fa-var-chess-bishop,\n \"face-grin-wink\": $fa-var-face-grin-wink,\n \"grin-wink\": $fa-var-grin-wink,\n \"ear-deaf\": $fa-var-ear-deaf,\n \"deaf\": $fa-var-deaf,\n \"deafness\": $fa-var-deafness,\n \"hard-of-hearing\": $fa-var-hard-of-hearing,\n \"road-circle-check\": $fa-var-road-circle-check,\n \"dice-five\": $fa-var-dice-five,\n \"square-rss\": $fa-var-square-rss,\n \"rss-square\": $fa-var-rss-square,\n \"land-mine-on\": $fa-var-land-mine-on,\n \"i-cursor\": $fa-var-i-cursor,\n \"stamp\": $fa-var-stamp,\n \"stairs\": $fa-var-stairs,\n \"i\": $fa-var-i,\n \"hryvnia-sign\": $fa-var-hryvnia-sign,\n \"hryvnia\": $fa-var-hryvnia,\n \"pills\": $fa-var-pills,\n \"face-grin-wide\": $fa-var-face-grin-wide,\n \"grin-alt\": $fa-var-grin-alt,\n \"tooth\": $fa-var-tooth,\n \"v\": $fa-var-v,\n \"bangladeshi-taka-sign\": $fa-var-bangladeshi-taka-sign,\n \"bicycle\": $fa-var-bicycle,\n \"staff-snake\": $fa-var-staff-snake,\n \"rod-asclepius\": $fa-var-rod-asclepius,\n \"rod-snake\": $fa-var-rod-snake,\n \"staff-aesculapius\": $fa-var-staff-aesculapius,\n \"head-side-cough-slash\": $fa-var-head-side-cough-slash,\n \"truck-medical\": $fa-var-truck-medical,\n \"ambulance\": $fa-var-ambulance,\n \"wheat-awn-circle-exclamation\": $fa-var-wheat-awn-circle-exclamation,\n \"snowman\": $fa-var-snowman,\n \"mortar-pestle\": $fa-var-mortar-pestle,\n \"road-barrier\": $fa-var-road-barrier,\n \"school\": $fa-var-school,\n \"igloo\": $fa-var-igloo,\n \"joint\": $fa-var-joint,\n \"angle-right\": $fa-var-angle-right,\n \"horse\": $fa-var-horse,\n \"q\": $fa-var-q,\n \"g\": $fa-var-g,\n \"notes-medical\": $fa-var-notes-medical,\n \"temperature-half\": $fa-var-temperature-half,\n \"temperature-2\": $fa-var-temperature-2,\n \"thermometer-2\": $fa-var-thermometer-2,\n \"thermometer-half\": $fa-var-thermometer-half,\n \"dong-sign\": $fa-var-dong-sign,\n \"capsules\": $fa-var-capsules,\n \"poo-storm\": $fa-var-poo-storm,\n \"poo-bolt\": $fa-var-poo-bolt,\n \"face-frown-open\": $fa-var-face-frown-open,\n \"frown-open\": $fa-var-frown-open,\n \"hand-point-up\": $fa-var-hand-point-up,\n \"money-bill\": $fa-var-money-bill,\n \"bookmark\": $fa-var-bookmark,\n \"align-justify\": $fa-var-align-justify,\n \"umbrella-beach\": $fa-var-umbrella-beach,\n \"helmet-un\": $fa-var-helmet-un,\n \"bullseye\": $fa-var-bullseye,\n \"bacon\": $fa-var-bacon,\n \"hand-point-down\": $fa-var-hand-point-down,\n \"arrow-up-from-bracket\": $fa-var-arrow-up-from-bracket,\n \"folder\": $fa-var-folder,\n \"folder-blank\": $fa-var-folder-blank,\n \"file-waveform\": $fa-var-file-waveform,\n \"file-medical-alt\": $fa-var-file-medical-alt,\n \"radiation\": $fa-var-radiation,\n \"chart-simple\": $fa-var-chart-simple,\n \"mars-stroke\": $fa-var-mars-stroke,\n \"vial\": $fa-var-vial,\n \"gauge\": $fa-var-gauge,\n \"dashboard\": $fa-var-dashboard,\n \"gauge-med\": $fa-var-gauge-med,\n \"tachometer-alt-average\": $fa-var-tachometer-alt-average,\n \"wand-magic-sparkles\": $fa-var-wand-magic-sparkles,\n \"magic-wand-sparkles\": $fa-var-magic-wand-sparkles,\n \"e\": $fa-var-e,\n \"pen-clip\": $fa-var-pen-clip,\n \"pen-alt\": $fa-var-pen-alt,\n \"bridge-circle-exclamation\": $fa-var-bridge-circle-exclamation,\n \"user\": $fa-var-user,\n \"school-circle-check\": $fa-var-school-circle-check,\n \"dumpster\": $fa-var-dumpster,\n \"van-shuttle\": $fa-var-van-shuttle,\n \"shuttle-van\": $fa-var-shuttle-van,\n \"building-user\": $fa-var-building-user,\n \"square-caret-left\": $fa-var-square-caret-left,\n \"caret-square-left\": $fa-var-caret-square-left,\n \"highlighter\": $fa-var-highlighter,\n \"key\": $fa-var-key,\n \"bullhorn\": $fa-var-bullhorn,\n \"globe\": $fa-var-globe,\n \"synagogue\": $fa-var-synagogue,\n \"person-half-dress\": $fa-var-person-half-dress,\n \"road-bridge\": $fa-var-road-bridge,\n \"location-arrow\": $fa-var-location-arrow,\n \"c\": $fa-var-c,\n \"tablet-button\": $fa-var-tablet-button,\n \"building-lock\": $fa-var-building-lock,\n \"pizza-slice\": $fa-var-pizza-slice,\n \"money-bill-wave\": $fa-var-money-bill-wave,\n \"chart-area\": $fa-var-chart-area,\n \"area-chart\": $fa-var-area-chart,\n \"house-flag\": $fa-var-house-flag,\n \"person-circle-minus\": $fa-var-person-circle-minus,\n \"ban\": $fa-var-ban,\n \"cancel\": $fa-var-cancel,\n \"camera-rotate\": $fa-var-camera-rotate,\n \"spray-can-sparkles\": $fa-var-spray-can-sparkles,\n \"air-freshener\": $fa-var-air-freshener,\n \"star\": $fa-var-star,\n \"repeat\": $fa-var-repeat,\n \"cross\": $fa-var-cross,\n \"box\": $fa-var-box,\n \"venus-mars\": $fa-var-venus-mars,\n \"arrow-pointer\": $fa-var-arrow-pointer,\n \"mouse-pointer\": $fa-var-mouse-pointer,\n \"maximize\": $fa-var-maximize,\n \"expand-arrows-alt\": $fa-var-expand-arrows-alt,\n \"charging-station\": $fa-var-charging-station,\n \"shapes\": $fa-var-shapes,\n \"triangle-circle-square\": $fa-var-triangle-circle-square,\n \"shuffle\": $fa-var-shuffle,\n \"random\": $fa-var-random,\n \"person-running\": $fa-var-person-running,\n \"running\": $fa-var-running,\n \"mobile-retro\": $fa-var-mobile-retro,\n \"grip-lines-vertical\": $fa-var-grip-lines-vertical,\n \"spider\": $fa-var-spider,\n \"hands-bound\": $fa-var-hands-bound,\n \"file-invoice-dollar\": $fa-var-file-invoice-dollar,\n \"plane-circle-exclamation\": $fa-var-plane-circle-exclamation,\n \"x-ray\": $fa-var-x-ray,\n \"spell-check\": $fa-var-spell-check,\n \"slash\": $fa-var-slash,\n \"computer-mouse\": $fa-var-computer-mouse,\n \"mouse\": $fa-var-mouse,\n \"arrow-right-to-bracket\": $fa-var-arrow-right-to-bracket,\n \"sign-in\": $fa-var-sign-in,\n \"shop-slash\": $fa-var-shop-slash,\n \"store-alt-slash\": $fa-var-store-alt-slash,\n \"server\": $fa-var-server,\n \"virus-covid-slash\": $fa-var-virus-covid-slash,\n \"shop-lock\": $fa-var-shop-lock,\n \"hourglass-start\": $fa-var-hourglass-start,\n \"hourglass-1\": $fa-var-hourglass-1,\n \"blender-phone\": $fa-var-blender-phone,\n \"building-wheat\": $fa-var-building-wheat,\n \"person-breastfeeding\": $fa-var-person-breastfeeding,\n \"right-to-bracket\": $fa-var-right-to-bracket,\n \"sign-in-alt\": $fa-var-sign-in-alt,\n \"venus\": $fa-var-venus,\n \"passport\": $fa-var-passport,\n \"thumbtack-slash\": $fa-var-thumbtack-slash,\n \"thumb-tack-slash\": $fa-var-thumb-tack-slash,\n \"heart-pulse\": $fa-var-heart-pulse,\n \"heartbeat\": $fa-var-heartbeat,\n \"people-carry-box\": $fa-var-people-carry-box,\n \"people-carry\": $fa-var-people-carry,\n \"temperature-high\": $fa-var-temperature-high,\n \"microchip\": $fa-var-microchip,\n \"crown\": $fa-var-crown,\n \"weight-hanging\": $fa-var-weight-hanging,\n \"xmarks-lines\": $fa-var-xmarks-lines,\n \"file-prescription\": $fa-var-file-prescription,\n \"weight-scale\": $fa-var-weight-scale,\n \"weight\": $fa-var-weight,\n \"user-group\": $fa-var-user-group,\n \"user-friends\": $fa-var-user-friends,\n \"arrow-up-a-z\": $fa-var-arrow-up-a-z,\n \"sort-alpha-up\": $fa-var-sort-alpha-up,\n \"chess-knight\": $fa-var-chess-knight,\n \"face-laugh-squint\": $fa-var-face-laugh-squint,\n \"laugh-squint\": $fa-var-laugh-squint,\n \"wheelchair\": $fa-var-wheelchair,\n \"circle-arrow-up\": $fa-var-circle-arrow-up,\n \"arrow-circle-up\": $fa-var-arrow-circle-up,\n \"toggle-on\": $fa-var-toggle-on,\n \"person-walking\": $fa-var-person-walking,\n \"walking\": $fa-var-walking,\n \"l\": $fa-var-l,\n \"fire\": $fa-var-fire,\n \"bed-pulse\": $fa-var-bed-pulse,\n \"procedures\": $fa-var-procedures,\n \"shuttle-space\": $fa-var-shuttle-space,\n \"space-shuttle\": $fa-var-space-shuttle,\n \"face-laugh\": $fa-var-face-laugh,\n \"laugh\": $fa-var-laugh,\n \"folder-open\": $fa-var-folder-open,\n \"heart-circle-plus\": $fa-var-heart-circle-plus,\n \"code-fork\": $fa-var-code-fork,\n \"city\": $fa-var-city,\n \"microphone-lines\": $fa-var-microphone-lines,\n \"microphone-alt\": $fa-var-microphone-alt,\n \"pepper-hot\": $fa-var-pepper-hot,\n \"unlock\": $fa-var-unlock,\n \"colon-sign\": $fa-var-colon-sign,\n \"headset\": $fa-var-headset,\n \"store-slash\": $fa-var-store-slash,\n \"road-circle-xmark\": $fa-var-road-circle-xmark,\n \"user-minus\": $fa-var-user-minus,\n \"mars-stroke-up\": $fa-var-mars-stroke-up,\n \"mars-stroke-v\": $fa-var-mars-stroke-v,\n \"champagne-glasses\": $fa-var-champagne-glasses,\n \"glass-cheers\": $fa-var-glass-cheers,\n \"clipboard\": $fa-var-clipboard,\n \"house-circle-exclamation\": $fa-var-house-circle-exclamation,\n \"file-arrow-up\": $fa-var-file-arrow-up,\n \"file-upload\": $fa-var-file-upload,\n \"wifi\": $fa-var-wifi,\n \"wifi-3\": $fa-var-wifi-3,\n \"wifi-strong\": $fa-var-wifi-strong,\n \"bath\": $fa-var-bath,\n \"bathtub\": $fa-var-bathtub,\n \"underline\": $fa-var-underline,\n \"user-pen\": $fa-var-user-pen,\n \"user-edit\": $fa-var-user-edit,\n \"signature\": $fa-var-signature,\n \"stroopwafel\": $fa-var-stroopwafel,\n \"bold\": $fa-var-bold,\n \"anchor-lock\": $fa-var-anchor-lock,\n \"building-ngo\": $fa-var-building-ngo,\n \"manat-sign\": $fa-var-manat-sign,\n \"not-equal\": $fa-var-not-equal,\n \"border-top-left\": $fa-var-border-top-left,\n \"border-style\": $fa-var-border-style,\n \"map-location-dot\": $fa-var-map-location-dot,\n \"map-marked-alt\": $fa-var-map-marked-alt,\n \"jedi\": $fa-var-jedi,\n \"square-poll-vertical\": $fa-var-square-poll-vertical,\n \"poll\": $fa-var-poll,\n \"mug-hot\": $fa-var-mug-hot,\n \"car-battery\": $fa-var-car-battery,\n \"battery-car\": $fa-var-battery-car,\n \"gift\": $fa-var-gift,\n \"dice-two\": $fa-var-dice-two,\n \"chess-queen\": $fa-var-chess-queen,\n \"glasses\": $fa-var-glasses,\n \"chess-board\": $fa-var-chess-board,\n \"building-circle-check\": $fa-var-building-circle-check,\n \"person-chalkboard\": $fa-var-person-chalkboard,\n \"mars-stroke-right\": $fa-var-mars-stroke-right,\n \"mars-stroke-h\": $fa-var-mars-stroke-h,\n \"hand-back-fist\": $fa-var-hand-back-fist,\n \"hand-rock\": $fa-var-hand-rock,\n \"square-caret-up\": $fa-var-square-caret-up,\n \"caret-square-up\": $fa-var-caret-square-up,\n \"cloud-showers-water\": $fa-var-cloud-showers-water,\n \"chart-bar\": $fa-var-chart-bar,\n \"bar-chart\": $fa-var-bar-chart,\n \"hands-bubbles\": $fa-var-hands-bubbles,\n \"hands-wash\": $fa-var-hands-wash,\n \"less-than-equal\": $fa-var-less-than-equal,\n \"train\": $fa-var-train,\n \"eye-low-vision\": $fa-var-eye-low-vision,\n \"low-vision\": $fa-var-low-vision,\n \"crow\": $fa-var-crow,\n \"sailboat\": $fa-var-sailboat,\n \"window-restore\": $fa-var-window-restore,\n \"square-plus\": $fa-var-square-plus,\n \"plus-square\": $fa-var-plus-square,\n \"torii-gate\": $fa-var-torii-gate,\n \"frog\": $fa-var-frog,\n \"bucket\": $fa-var-bucket,\n \"image\": $fa-var-image,\n \"microphone\": $fa-var-microphone,\n \"cow\": $fa-var-cow,\n \"caret-up\": $fa-var-caret-up,\n \"screwdriver\": $fa-var-screwdriver,\n \"folder-closed\": $fa-var-folder-closed,\n \"house-tsunami\": $fa-var-house-tsunami,\n \"square-nfi\": $fa-var-square-nfi,\n \"arrow-up-from-ground-water\": $fa-var-arrow-up-from-ground-water,\n \"martini-glass\": $fa-var-martini-glass,\n \"glass-martini-alt\": $fa-var-glass-martini-alt,\n \"square-binary\": $fa-var-square-binary,\n \"rotate-left\": $fa-var-rotate-left,\n \"rotate-back\": $fa-var-rotate-back,\n \"rotate-backward\": $fa-var-rotate-backward,\n \"undo-alt\": $fa-var-undo-alt,\n \"table-columns\": $fa-var-table-columns,\n \"columns\": $fa-var-columns,\n \"lemon\": $fa-var-lemon,\n \"head-side-mask\": $fa-var-head-side-mask,\n \"handshake\": $fa-var-handshake,\n \"gem\": $fa-var-gem,\n \"dolly\": $fa-var-dolly,\n \"dolly-box\": $fa-var-dolly-box,\n \"smoking\": $fa-var-smoking,\n \"minimize\": $fa-var-minimize,\n \"compress-arrows-alt\": $fa-var-compress-arrows-alt,\n \"monument\": $fa-var-monument,\n \"snowplow\": $fa-var-snowplow,\n \"angles-right\": $fa-var-angles-right,\n \"angle-double-right\": $fa-var-angle-double-right,\n \"cannabis\": $fa-var-cannabis,\n \"circle-play\": $fa-var-circle-play,\n \"play-circle\": $fa-var-play-circle,\n \"tablets\": $fa-var-tablets,\n \"ethernet\": $fa-var-ethernet,\n \"euro-sign\": $fa-var-euro-sign,\n \"eur\": $fa-var-eur,\n \"euro\": $fa-var-euro,\n \"chair\": $fa-var-chair,\n \"circle-check\": $fa-var-circle-check,\n \"check-circle\": $fa-var-check-circle,\n \"circle-stop\": $fa-var-circle-stop,\n \"stop-circle\": $fa-var-stop-circle,\n \"compass-drafting\": $fa-var-compass-drafting,\n \"drafting-compass\": $fa-var-drafting-compass,\n \"plate-wheat\": $fa-var-plate-wheat,\n \"icicles\": $fa-var-icicles,\n \"person-shelter\": $fa-var-person-shelter,\n \"neuter\": $fa-var-neuter,\n \"id-badge\": $fa-var-id-badge,\n \"marker\": $fa-var-marker,\n \"face-laugh-beam\": $fa-var-face-laugh-beam,\n \"laugh-beam\": $fa-var-laugh-beam,\n \"helicopter-symbol\": $fa-var-helicopter-symbol,\n \"universal-access\": $fa-var-universal-access,\n \"circle-chevron-up\": $fa-var-circle-chevron-up,\n \"chevron-circle-up\": $fa-var-chevron-circle-up,\n \"lari-sign\": $fa-var-lari-sign,\n \"volcano\": $fa-var-volcano,\n \"person-walking-dashed-line-arrow-right\": $fa-var-person-walking-dashed-line-arrow-right,\n \"sterling-sign\": $fa-var-sterling-sign,\n \"gbp\": $fa-var-gbp,\n \"pound-sign\": $fa-var-pound-sign,\n \"viruses\": $fa-var-viruses,\n \"square-person-confined\": $fa-var-square-person-confined,\n \"user-tie\": $fa-var-user-tie,\n \"arrow-down-long\": $fa-var-arrow-down-long,\n \"long-arrow-down\": $fa-var-long-arrow-down,\n \"tent-arrow-down-to-line\": $fa-var-tent-arrow-down-to-line,\n \"certificate\": $fa-var-certificate,\n \"reply-all\": $fa-var-reply-all,\n \"mail-reply-all\": $fa-var-mail-reply-all,\n \"suitcase\": $fa-var-suitcase,\n \"person-skating\": $fa-var-person-skating,\n \"skating\": $fa-var-skating,\n \"filter-circle-dollar\": $fa-var-filter-circle-dollar,\n \"funnel-dollar\": $fa-var-funnel-dollar,\n \"camera-retro\": $fa-var-camera-retro,\n \"circle-arrow-down\": $fa-var-circle-arrow-down,\n \"arrow-circle-down\": $fa-var-arrow-circle-down,\n \"file-import\": $fa-var-file-import,\n \"arrow-right-to-file\": $fa-var-arrow-right-to-file,\n \"square-arrow-up-right\": $fa-var-square-arrow-up-right,\n \"external-link-square\": $fa-var-external-link-square,\n \"box-open\": $fa-var-box-open,\n \"scroll\": $fa-var-scroll,\n \"spa\": $fa-var-spa,\n \"location-pin-lock\": $fa-var-location-pin-lock,\n \"pause\": $fa-var-pause,\n \"hill-avalanche\": $fa-var-hill-avalanche,\n \"temperature-empty\": $fa-var-temperature-empty,\n \"temperature-0\": $fa-var-temperature-0,\n \"thermometer-0\": $fa-var-thermometer-0,\n \"thermometer-empty\": $fa-var-thermometer-empty,\n \"bomb\": $fa-var-bomb,\n \"registered\": $fa-var-registered,\n \"address-card\": $fa-var-address-card,\n \"contact-card\": $fa-var-contact-card,\n \"vcard\": $fa-var-vcard,\n \"scale-unbalanced-flip\": $fa-var-scale-unbalanced-flip,\n \"balance-scale-right\": $fa-var-balance-scale-right,\n \"subscript\": $fa-var-subscript,\n \"diamond-turn-right\": $fa-var-diamond-turn-right,\n \"directions\": $fa-var-directions,\n \"burst\": $fa-var-burst,\n \"house-laptop\": $fa-var-house-laptop,\n \"laptop-house\": $fa-var-laptop-house,\n \"face-tired\": $fa-var-face-tired,\n \"tired\": $fa-var-tired,\n \"money-bills\": $fa-var-money-bills,\n \"smog\": $fa-var-smog,\n \"crutch\": $fa-var-crutch,\n \"cloud-arrow-up\": $fa-var-cloud-arrow-up,\n \"cloud-upload\": $fa-var-cloud-upload,\n \"cloud-upload-alt\": $fa-var-cloud-upload-alt,\n \"palette\": $fa-var-palette,\n \"arrows-turn-right\": $fa-var-arrows-turn-right,\n \"vest\": $fa-var-vest,\n \"ferry\": $fa-var-ferry,\n \"arrows-down-to-people\": $fa-var-arrows-down-to-people,\n \"seedling\": $fa-var-seedling,\n \"sprout\": $fa-var-sprout,\n \"left-right\": $fa-var-left-right,\n \"arrows-alt-h\": $fa-var-arrows-alt-h,\n \"boxes-packing\": $fa-var-boxes-packing,\n \"circle-arrow-left\": $fa-var-circle-arrow-left,\n \"arrow-circle-left\": $fa-var-arrow-circle-left,\n \"group-arrows-rotate\": $fa-var-group-arrows-rotate,\n \"bowl-food\": $fa-var-bowl-food,\n \"candy-cane\": $fa-var-candy-cane,\n \"arrow-down-wide-short\": $fa-var-arrow-down-wide-short,\n \"sort-amount-asc\": $fa-var-sort-amount-asc,\n \"sort-amount-down\": $fa-var-sort-amount-down,\n \"cloud-bolt\": $fa-var-cloud-bolt,\n \"thunderstorm\": $fa-var-thunderstorm,\n \"text-slash\": $fa-var-text-slash,\n \"remove-format\": $fa-var-remove-format,\n \"face-smile-wink\": $fa-var-face-smile-wink,\n \"smile-wink\": $fa-var-smile-wink,\n \"file-word\": $fa-var-file-word,\n \"file-powerpoint\": $fa-var-file-powerpoint,\n \"arrows-left-right\": $fa-var-arrows-left-right,\n \"arrows-h\": $fa-var-arrows-h,\n \"house-lock\": $fa-var-house-lock,\n \"cloud-arrow-down\": $fa-var-cloud-arrow-down,\n \"cloud-download\": $fa-var-cloud-download,\n \"cloud-download-alt\": $fa-var-cloud-download-alt,\n \"children\": $fa-var-children,\n \"chalkboard\": $fa-var-chalkboard,\n \"blackboard\": $fa-var-blackboard,\n \"user-large-slash\": $fa-var-user-large-slash,\n \"user-alt-slash\": $fa-var-user-alt-slash,\n \"envelope-open\": $fa-var-envelope-open,\n \"handshake-simple-slash\": $fa-var-handshake-simple-slash,\n \"handshake-alt-slash\": $fa-var-handshake-alt-slash,\n \"mattress-pillow\": $fa-var-mattress-pillow,\n \"guarani-sign\": $fa-var-guarani-sign,\n \"arrows-rotate\": $fa-var-arrows-rotate,\n \"refresh\": $fa-var-refresh,\n \"sync\": $fa-var-sync,\n \"fire-extinguisher\": $fa-var-fire-extinguisher,\n \"cruzeiro-sign\": $fa-var-cruzeiro-sign,\n \"greater-than-equal\": $fa-var-greater-than-equal,\n \"shield-halved\": $fa-var-shield-halved,\n \"shield-alt\": $fa-var-shield-alt,\n \"book-atlas\": $fa-var-book-atlas,\n \"atlas\": $fa-var-atlas,\n \"virus\": $fa-var-virus,\n \"envelope-circle-check\": $fa-var-envelope-circle-check,\n \"layer-group\": $fa-var-layer-group,\n \"arrows-to-dot\": $fa-var-arrows-to-dot,\n \"archway\": $fa-var-archway,\n \"heart-circle-check\": $fa-var-heart-circle-check,\n \"house-chimney-crack\": $fa-var-house-chimney-crack,\n \"house-damage\": $fa-var-house-damage,\n \"file-zipper\": $fa-var-file-zipper,\n \"file-archive\": $fa-var-file-archive,\n \"square\": $fa-var-square,\n \"martini-glass-empty\": $fa-var-martini-glass-empty,\n \"glass-martini\": $fa-var-glass-martini,\n \"couch\": $fa-var-couch,\n \"cedi-sign\": $fa-var-cedi-sign,\n \"italic\": $fa-var-italic,\n \"table-cells-column-lock\": $fa-var-table-cells-column-lock,\n \"church\": $fa-var-church,\n \"comments-dollar\": $fa-var-comments-dollar,\n \"democrat\": $fa-var-democrat,\n \"z\": $fa-var-z,\n \"person-skiing\": $fa-var-person-skiing,\n \"skiing\": $fa-var-skiing,\n \"road-lock\": $fa-var-road-lock,\n \"a\": $fa-var-a,\n \"temperature-arrow-down\": $fa-var-temperature-arrow-down,\n \"temperature-down\": $fa-var-temperature-down,\n \"feather-pointed\": $fa-var-feather-pointed,\n \"feather-alt\": $fa-var-feather-alt,\n \"p\": $fa-var-p,\n \"snowflake\": $fa-var-snowflake,\n \"newspaper\": $fa-var-newspaper,\n \"rectangle-ad\": $fa-var-rectangle-ad,\n \"ad\": $fa-var-ad,\n \"circle-arrow-right\": $fa-var-circle-arrow-right,\n \"arrow-circle-right\": $fa-var-arrow-circle-right,\n \"filter-circle-xmark\": $fa-var-filter-circle-xmark,\n \"locust\": $fa-var-locust,\n \"sort\": $fa-var-sort,\n \"unsorted\": $fa-var-unsorted,\n \"list-ol\": $fa-var-list-ol,\n \"list-1-2\": $fa-var-list-1-2,\n \"list-numeric\": $fa-var-list-numeric,\n \"person-dress-burst\": $fa-var-person-dress-burst,\n \"money-check-dollar\": $fa-var-money-check-dollar,\n \"money-check-alt\": $fa-var-money-check-alt,\n \"vector-square\": $fa-var-vector-square,\n \"bread-slice\": $fa-var-bread-slice,\n \"language\": $fa-var-language,\n \"face-kiss-wink-heart\": $fa-var-face-kiss-wink-heart,\n \"kiss-wink-heart\": $fa-var-kiss-wink-heart,\n \"filter\": $fa-var-filter,\n \"question\": $fa-var-question,\n \"file-signature\": $fa-var-file-signature,\n \"up-down-left-right\": $fa-var-up-down-left-right,\n \"arrows-alt\": $fa-var-arrows-alt,\n \"house-chimney-user\": $fa-var-house-chimney-user,\n \"hand-holding-heart\": $fa-var-hand-holding-heart,\n \"puzzle-piece\": $fa-var-puzzle-piece,\n \"money-check\": $fa-var-money-check,\n \"star-half-stroke\": $fa-var-star-half-stroke,\n \"star-half-alt\": $fa-var-star-half-alt,\n \"code\": $fa-var-code,\n \"whiskey-glass\": $fa-var-whiskey-glass,\n \"glass-whiskey\": $fa-var-glass-whiskey,\n \"building-circle-exclamation\": $fa-var-building-circle-exclamation,\n \"magnifying-glass-chart\": $fa-var-magnifying-glass-chart,\n \"arrow-up-right-from-square\": $fa-var-arrow-up-right-from-square,\n \"external-link\": $fa-var-external-link,\n \"cubes-stacked\": $fa-var-cubes-stacked,\n \"won-sign\": $fa-var-won-sign,\n \"krw\": $fa-var-krw,\n \"won\": $fa-var-won,\n \"virus-covid\": $fa-var-virus-covid,\n \"austral-sign\": $fa-var-austral-sign,\n \"f\": $fa-var-f,\n \"leaf\": $fa-var-leaf,\n \"road\": $fa-var-road,\n \"taxi\": $fa-var-taxi,\n \"cab\": $fa-var-cab,\n \"person-circle-plus\": $fa-var-person-circle-plus,\n \"chart-pie\": $fa-var-chart-pie,\n \"pie-chart\": $fa-var-pie-chart,\n \"bolt-lightning\": $fa-var-bolt-lightning,\n \"sack-xmark\": $fa-var-sack-xmark,\n \"file-excel\": $fa-var-file-excel,\n \"file-contract\": $fa-var-file-contract,\n \"fish-fins\": $fa-var-fish-fins,\n \"building-flag\": $fa-var-building-flag,\n \"face-grin-beam\": $fa-var-face-grin-beam,\n \"grin-beam\": $fa-var-grin-beam,\n \"object-ungroup\": $fa-var-object-ungroup,\n \"poop\": $fa-var-poop,\n \"location-pin\": $fa-var-location-pin,\n \"map-marker\": $fa-var-map-marker,\n \"kaaba\": $fa-var-kaaba,\n \"toilet-paper\": $fa-var-toilet-paper,\n \"helmet-safety\": $fa-var-helmet-safety,\n \"hard-hat\": $fa-var-hard-hat,\n \"hat-hard\": $fa-var-hat-hard,\n \"eject\": $fa-var-eject,\n \"circle-right\": $fa-var-circle-right,\n \"arrow-alt-circle-right\": $fa-var-arrow-alt-circle-right,\n \"plane-circle-check\": $fa-var-plane-circle-check,\n \"face-rolling-eyes\": $fa-var-face-rolling-eyes,\n \"meh-rolling-eyes\": $fa-var-meh-rolling-eyes,\n \"object-group\": $fa-var-object-group,\n \"chart-line\": $fa-var-chart-line,\n \"line-chart\": $fa-var-line-chart,\n \"mask-ventilator\": $fa-var-mask-ventilator,\n \"arrow-right\": $fa-var-arrow-right,\n \"signs-post\": $fa-var-signs-post,\n \"map-signs\": $fa-var-map-signs,\n \"cash-register\": $fa-var-cash-register,\n \"person-circle-question\": $fa-var-person-circle-question,\n \"h\": $fa-var-h,\n \"tarp\": $fa-var-tarp,\n \"screwdriver-wrench\": $fa-var-screwdriver-wrench,\n \"tools\": $fa-var-tools,\n \"arrows-to-eye\": $fa-var-arrows-to-eye,\n \"plug-circle-bolt\": $fa-var-plug-circle-bolt,\n \"heart\": $fa-var-heart,\n \"mars-and-venus\": $fa-var-mars-and-venus,\n \"house-user\": $fa-var-house-user,\n \"home-user\": $fa-var-home-user,\n \"dumpster-fire\": $fa-var-dumpster-fire,\n \"house-crack\": $fa-var-house-crack,\n \"martini-glass-citrus\": $fa-var-martini-glass-citrus,\n \"cocktail\": $fa-var-cocktail,\n \"face-surprise\": $fa-var-face-surprise,\n \"surprise\": $fa-var-surprise,\n \"bottle-water\": $fa-var-bottle-water,\n \"circle-pause\": $fa-var-circle-pause,\n \"pause-circle\": $fa-var-pause-circle,\n \"toilet-paper-slash\": $fa-var-toilet-paper-slash,\n \"apple-whole\": $fa-var-apple-whole,\n \"apple-alt\": $fa-var-apple-alt,\n \"kitchen-set\": $fa-var-kitchen-set,\n \"r\": $fa-var-r,\n \"temperature-quarter\": $fa-var-temperature-quarter,\n \"temperature-1\": $fa-var-temperature-1,\n \"thermometer-1\": $fa-var-thermometer-1,\n \"thermometer-quarter\": $fa-var-thermometer-quarter,\n \"cube\": $fa-var-cube,\n \"bitcoin-sign\": $fa-var-bitcoin-sign,\n \"shield-dog\": $fa-var-shield-dog,\n \"solar-panel\": $fa-var-solar-panel,\n \"lock-open\": $fa-var-lock-open,\n \"elevator\": $fa-var-elevator,\n \"money-bill-transfer\": $fa-var-money-bill-transfer,\n \"money-bill-trend-up\": $fa-var-money-bill-trend-up,\n \"house-flood-water-circle-arrow-right\": $fa-var-house-flood-water-circle-arrow-right,\n \"square-poll-horizontal\": $fa-var-square-poll-horizontal,\n \"poll-h\": $fa-var-poll-h,\n \"circle\": $fa-var-circle,\n \"backward-fast\": $fa-var-backward-fast,\n \"fast-backward\": $fa-var-fast-backward,\n \"recycle\": $fa-var-recycle,\n \"user-astronaut\": $fa-var-user-astronaut,\n \"plane-slash\": $fa-var-plane-slash,\n \"trademark\": $fa-var-trademark,\n \"basketball\": $fa-var-basketball,\n \"basketball-ball\": $fa-var-basketball-ball,\n \"satellite-dish\": $fa-var-satellite-dish,\n \"circle-up\": $fa-var-circle-up,\n \"arrow-alt-circle-up\": $fa-var-arrow-alt-circle-up,\n \"mobile-screen-button\": $fa-var-mobile-screen-button,\n \"mobile-alt\": $fa-var-mobile-alt,\n \"volume-high\": $fa-var-volume-high,\n \"volume-up\": $fa-var-volume-up,\n \"users-rays\": $fa-var-users-rays,\n \"wallet\": $fa-var-wallet,\n \"clipboard-check\": $fa-var-clipboard-check,\n \"file-audio\": $fa-var-file-audio,\n \"burger\": $fa-var-burger,\n \"hamburger\": $fa-var-hamburger,\n \"wrench\": $fa-var-wrench,\n \"bugs\": $fa-var-bugs,\n \"rupee-sign\": $fa-var-rupee-sign,\n \"rupee\": $fa-var-rupee,\n \"file-image\": $fa-var-file-image,\n \"circle-question\": $fa-var-circle-question,\n \"question-circle\": $fa-var-question-circle,\n \"plane-departure\": $fa-var-plane-departure,\n \"handshake-slash\": $fa-var-handshake-slash,\n \"book-bookmark\": $fa-var-book-bookmark,\n \"code-branch\": $fa-var-code-branch,\n \"hat-cowboy\": $fa-var-hat-cowboy,\n \"bridge\": $fa-var-bridge,\n \"phone-flip\": $fa-var-phone-flip,\n \"phone-alt\": $fa-var-phone-alt,\n \"truck-front\": $fa-var-truck-front,\n \"cat\": $fa-var-cat,\n \"anchor-circle-exclamation\": $fa-var-anchor-circle-exclamation,\n \"truck-field\": $fa-var-truck-field,\n \"route\": $fa-var-route,\n \"clipboard-question\": $fa-var-clipboard-question,\n \"panorama\": $fa-var-panorama,\n \"comment-medical\": $fa-var-comment-medical,\n \"teeth-open\": $fa-var-teeth-open,\n \"file-circle-minus\": $fa-var-file-circle-minus,\n \"tags\": $fa-var-tags,\n \"wine-glass\": $fa-var-wine-glass,\n \"forward-fast\": $fa-var-forward-fast,\n \"fast-forward\": $fa-var-fast-forward,\n \"face-meh-blank\": $fa-var-face-meh-blank,\n \"meh-blank\": $fa-var-meh-blank,\n \"square-parking\": $fa-var-square-parking,\n \"parking\": $fa-var-parking,\n \"house-signal\": $fa-var-house-signal,\n \"bars-progress\": $fa-var-bars-progress,\n \"tasks-alt\": $fa-var-tasks-alt,\n \"faucet-drip\": $fa-var-faucet-drip,\n \"cart-flatbed\": $fa-var-cart-flatbed,\n \"dolly-flatbed\": $fa-var-dolly-flatbed,\n \"ban-smoking\": $fa-var-ban-smoking,\n \"smoking-ban\": $fa-var-smoking-ban,\n \"terminal\": $fa-var-terminal,\n \"mobile-button\": $fa-var-mobile-button,\n \"house-medical-flag\": $fa-var-house-medical-flag,\n \"basket-shopping\": $fa-var-basket-shopping,\n \"shopping-basket\": $fa-var-shopping-basket,\n \"tape\": $fa-var-tape,\n \"bus-simple\": $fa-var-bus-simple,\n \"bus-alt\": $fa-var-bus-alt,\n \"eye\": $fa-var-eye,\n \"face-sad-cry\": $fa-var-face-sad-cry,\n \"sad-cry\": $fa-var-sad-cry,\n \"audio-description\": $fa-var-audio-description,\n \"person-military-to-person\": $fa-var-person-military-to-person,\n \"file-shield\": $fa-var-file-shield,\n \"user-slash\": $fa-var-user-slash,\n \"pen\": $fa-var-pen,\n \"tower-observation\": $fa-var-tower-observation,\n \"file-code\": $fa-var-file-code,\n \"signal\": $fa-var-signal,\n \"signal-5\": $fa-var-signal-5,\n \"signal-perfect\": $fa-var-signal-perfect,\n \"bus\": $fa-var-bus,\n \"heart-circle-xmark\": $fa-var-heart-circle-xmark,\n \"house-chimney\": $fa-var-house-chimney,\n \"home-lg\": $fa-var-home-lg,\n \"window-maximize\": $fa-var-window-maximize,\n \"face-frown\": $fa-var-face-frown,\n \"frown\": $fa-var-frown,\n \"prescription\": $fa-var-prescription,\n \"shop\": $fa-var-shop,\n \"store-alt\": $fa-var-store-alt,\n \"floppy-disk\": $fa-var-floppy-disk,\n \"save\": $fa-var-save,\n \"vihara\": $fa-var-vihara,\n \"scale-unbalanced\": $fa-var-scale-unbalanced,\n \"balance-scale-left\": $fa-var-balance-scale-left,\n \"sort-up\": $fa-var-sort-up,\n \"sort-asc\": $fa-var-sort-asc,\n \"comment-dots\": $fa-var-comment-dots,\n \"commenting\": $fa-var-commenting,\n \"plant-wilt\": $fa-var-plant-wilt,\n \"diamond\": $fa-var-diamond,\n \"face-grin-squint\": $fa-var-face-grin-squint,\n \"grin-squint\": $fa-var-grin-squint,\n \"hand-holding-dollar\": $fa-var-hand-holding-dollar,\n \"hand-holding-usd\": $fa-var-hand-holding-usd,\n \"chart-diagram\": $fa-var-chart-diagram,\n \"bacterium\": $fa-var-bacterium,\n \"hand-pointer\": $fa-var-hand-pointer,\n \"drum-steelpan\": $fa-var-drum-steelpan,\n \"hand-scissors\": $fa-var-hand-scissors,\n \"hands-praying\": $fa-var-hands-praying,\n \"praying-hands\": $fa-var-praying-hands,\n \"arrow-rotate-right\": $fa-var-arrow-rotate-right,\n \"arrow-right-rotate\": $fa-var-arrow-right-rotate,\n \"arrow-rotate-forward\": $fa-var-arrow-rotate-forward,\n \"redo\": $fa-var-redo,\n \"biohazard\": $fa-var-biohazard,\n \"location-crosshairs\": $fa-var-location-crosshairs,\n \"location\": $fa-var-location,\n \"mars-double\": $fa-var-mars-double,\n \"child-dress\": $fa-var-child-dress,\n \"users-between-lines\": $fa-var-users-between-lines,\n \"lungs-virus\": $fa-var-lungs-virus,\n \"face-grin-tears\": $fa-var-face-grin-tears,\n \"grin-tears\": $fa-var-grin-tears,\n \"phone\": $fa-var-phone,\n \"calendar-xmark\": $fa-var-calendar-xmark,\n \"calendar-times\": $fa-var-calendar-times,\n \"child-reaching\": $fa-var-child-reaching,\n \"head-side-virus\": $fa-var-head-side-virus,\n \"user-gear\": $fa-var-user-gear,\n \"user-cog\": $fa-var-user-cog,\n \"arrow-up-1-9\": $fa-var-arrow-up-1-9,\n \"sort-numeric-up\": $fa-var-sort-numeric-up,\n \"door-closed\": $fa-var-door-closed,\n \"shield-virus\": $fa-var-shield-virus,\n \"dice-six\": $fa-var-dice-six,\n \"mosquito-net\": $fa-var-mosquito-net,\n \"file-fragment\": $fa-var-file-fragment,\n \"bridge-water\": $fa-var-bridge-water,\n \"person-booth\": $fa-var-person-booth,\n \"text-width\": $fa-var-text-width,\n \"hat-wizard\": $fa-var-hat-wizard,\n \"pen-fancy\": $fa-var-pen-fancy,\n \"person-digging\": $fa-var-person-digging,\n \"digging\": $fa-var-digging,\n \"trash\": $fa-var-trash,\n \"gauge-simple\": $fa-var-gauge-simple,\n \"gauge-simple-med\": $fa-var-gauge-simple-med,\n \"tachometer-average\": $fa-var-tachometer-average,\n \"book-medical\": $fa-var-book-medical,\n \"poo\": $fa-var-poo,\n \"quote-right\": $fa-var-quote-right,\n \"quote-right-alt\": $fa-var-quote-right-alt,\n \"shirt\": $fa-var-shirt,\n \"t-shirt\": $fa-var-t-shirt,\n \"tshirt\": $fa-var-tshirt,\n \"cubes\": $fa-var-cubes,\n \"divide\": $fa-var-divide,\n \"tenge-sign\": $fa-var-tenge-sign,\n \"tenge\": $fa-var-tenge,\n \"headphones\": $fa-var-headphones,\n \"hands-holding\": $fa-var-hands-holding,\n \"hands-clapping\": $fa-var-hands-clapping,\n \"republican\": $fa-var-republican,\n \"arrow-left\": $fa-var-arrow-left,\n \"person-circle-xmark\": $fa-var-person-circle-xmark,\n \"ruler\": $fa-var-ruler,\n \"align-left\": $fa-var-align-left,\n \"dice-d6\": $fa-var-dice-d6,\n \"restroom\": $fa-var-restroom,\n \"j\": $fa-var-j,\n \"users-viewfinder\": $fa-var-users-viewfinder,\n \"file-video\": $fa-var-file-video,\n \"up-right-from-square\": $fa-var-up-right-from-square,\n \"external-link-alt\": $fa-var-external-link-alt,\n \"table-cells\": $fa-var-table-cells,\n \"th\": $fa-var-th,\n \"file-pdf\": $fa-var-file-pdf,\n \"book-bible\": $fa-var-book-bible,\n \"bible\": $fa-var-bible,\n \"o\": $fa-var-o,\n \"suitcase-medical\": $fa-var-suitcase-medical,\n \"medkit\": $fa-var-medkit,\n \"user-secret\": $fa-var-user-secret,\n \"otter\": $fa-var-otter,\n \"person-dress\": $fa-var-person-dress,\n \"female\": $fa-var-female,\n \"comment-dollar\": $fa-var-comment-dollar,\n \"business-time\": $fa-var-business-time,\n \"briefcase-clock\": $fa-var-briefcase-clock,\n \"table-cells-large\": $fa-var-table-cells-large,\n \"th-large\": $fa-var-th-large,\n \"book-tanakh\": $fa-var-book-tanakh,\n \"tanakh\": $fa-var-tanakh,\n \"phone-volume\": $fa-var-phone-volume,\n \"volume-control-phone\": $fa-var-volume-control-phone,\n \"hat-cowboy-side\": $fa-var-hat-cowboy-side,\n \"clipboard-user\": $fa-var-clipboard-user,\n \"child\": $fa-var-child,\n \"lira-sign\": $fa-var-lira-sign,\n \"satellite\": $fa-var-satellite,\n \"plane-lock\": $fa-var-plane-lock,\n \"tag\": $fa-var-tag,\n \"comment\": $fa-var-comment,\n \"cake-candles\": $fa-var-cake-candles,\n \"birthday-cake\": $fa-var-birthday-cake,\n \"cake\": $fa-var-cake,\n \"envelope\": $fa-var-envelope,\n \"angles-up\": $fa-var-angles-up,\n \"angle-double-up\": $fa-var-angle-double-up,\n \"paperclip\": $fa-var-paperclip,\n \"arrow-right-to-city\": $fa-var-arrow-right-to-city,\n \"ribbon\": $fa-var-ribbon,\n \"lungs\": $fa-var-lungs,\n \"arrow-up-9-1\": $fa-var-arrow-up-9-1,\n \"sort-numeric-up-alt\": $fa-var-sort-numeric-up-alt,\n \"litecoin-sign\": $fa-var-litecoin-sign,\n \"border-none\": $fa-var-border-none,\n \"circle-nodes\": $fa-var-circle-nodes,\n \"parachute-box\": $fa-var-parachute-box,\n \"indent\": $fa-var-indent,\n \"truck-field-un\": $fa-var-truck-field-un,\n \"hourglass\": $fa-var-hourglass,\n \"hourglass-empty\": $fa-var-hourglass-empty,\n \"mountain\": $fa-var-mountain,\n \"user-doctor\": $fa-var-user-doctor,\n \"user-md\": $fa-var-user-md,\n \"circle-info\": $fa-var-circle-info,\n \"info-circle\": $fa-var-info-circle,\n \"cloud-meatball\": $fa-var-cloud-meatball,\n \"camera\": $fa-var-camera,\n \"camera-alt\": $fa-var-camera-alt,\n \"square-virus\": $fa-var-square-virus,\n \"meteor\": $fa-var-meteor,\n \"car-on\": $fa-var-car-on,\n \"sleigh\": $fa-var-sleigh,\n \"arrow-down-1-9\": $fa-var-arrow-down-1-9,\n \"sort-numeric-asc\": $fa-var-sort-numeric-asc,\n \"sort-numeric-down\": $fa-var-sort-numeric-down,\n \"hand-holding-droplet\": $fa-var-hand-holding-droplet,\n \"hand-holding-water\": $fa-var-hand-holding-water,\n \"water\": $fa-var-water,\n \"calendar-check\": $fa-var-calendar-check,\n \"braille\": $fa-var-braille,\n \"prescription-bottle-medical\": $fa-var-prescription-bottle-medical,\n \"prescription-bottle-alt\": $fa-var-prescription-bottle-alt,\n \"landmark\": $fa-var-landmark,\n \"truck\": $fa-var-truck,\n \"crosshairs\": $fa-var-crosshairs,\n \"person-cane\": $fa-var-person-cane,\n \"tent\": $fa-var-tent,\n \"vest-patches\": $fa-var-vest-patches,\n \"check-double\": $fa-var-check-double,\n \"arrow-down-a-z\": $fa-var-arrow-down-a-z,\n \"sort-alpha-asc\": $fa-var-sort-alpha-asc,\n \"sort-alpha-down\": $fa-var-sort-alpha-down,\n \"money-bill-wheat\": $fa-var-money-bill-wheat,\n \"cookie\": $fa-var-cookie,\n \"arrow-rotate-left\": $fa-var-arrow-rotate-left,\n \"arrow-left-rotate\": $fa-var-arrow-left-rotate,\n \"arrow-rotate-back\": $fa-var-arrow-rotate-back,\n \"arrow-rotate-backward\": $fa-var-arrow-rotate-backward,\n \"undo\": $fa-var-undo,\n \"hard-drive\": $fa-var-hard-drive,\n \"hdd\": $fa-var-hdd,\n \"face-grin-squint-tears\": $fa-var-face-grin-squint-tears,\n \"grin-squint-tears\": $fa-var-grin-squint-tears,\n \"dumbbell\": $fa-var-dumbbell,\n \"rectangle-list\": $fa-var-rectangle-list,\n \"list-alt\": $fa-var-list-alt,\n \"tarp-droplet\": $fa-var-tarp-droplet,\n \"house-medical-circle-check\": $fa-var-house-medical-circle-check,\n \"person-skiing-nordic\": $fa-var-person-skiing-nordic,\n \"skiing-nordic\": $fa-var-skiing-nordic,\n \"calendar-plus\": $fa-var-calendar-plus,\n \"plane-arrival\": $fa-var-plane-arrival,\n \"circle-left\": $fa-var-circle-left,\n \"arrow-alt-circle-left\": $fa-var-arrow-alt-circle-left,\n \"train-subway\": $fa-var-train-subway,\n \"subway\": $fa-var-subway,\n \"chart-gantt\": $fa-var-chart-gantt,\n \"indian-rupee-sign\": $fa-var-indian-rupee-sign,\n \"indian-rupee\": $fa-var-indian-rupee,\n \"inr\": $fa-var-inr,\n \"crop-simple\": $fa-var-crop-simple,\n \"crop-alt\": $fa-var-crop-alt,\n \"money-bill-1\": $fa-var-money-bill-1,\n \"money-bill-alt\": $fa-var-money-bill-alt,\n \"left-long\": $fa-var-left-long,\n \"long-arrow-alt-left\": $fa-var-long-arrow-alt-left,\n \"dna\": $fa-var-dna,\n \"virus-slash\": $fa-var-virus-slash,\n \"minus\": $fa-var-minus,\n \"subtract\": $fa-var-subtract,\n \"chess\": $fa-var-chess,\n \"arrow-left-long\": $fa-var-arrow-left-long,\n \"long-arrow-left\": $fa-var-long-arrow-left,\n \"plug-circle-check\": $fa-var-plug-circle-check,\n \"street-view\": $fa-var-street-view,\n \"franc-sign\": $fa-var-franc-sign,\n \"volume-off\": $fa-var-volume-off,\n \"hands-asl-interpreting\": $fa-var-hands-asl-interpreting,\n \"american-sign-language-interpreting\": $fa-var-american-sign-language-interpreting,\n \"asl-interpreting\": $fa-var-asl-interpreting,\n \"hands-american-sign-language-interpreting\": $fa-var-hands-american-sign-language-interpreting,\n \"gear\": $fa-var-gear,\n \"cog\": $fa-var-cog,\n \"droplet-slash\": $fa-var-droplet-slash,\n \"tint-slash\": $fa-var-tint-slash,\n \"mosque\": $fa-var-mosque,\n \"mosquito\": $fa-var-mosquito,\n \"star-of-david\": $fa-var-star-of-david,\n \"person-military-rifle\": $fa-var-person-military-rifle,\n \"cart-shopping\": $fa-var-cart-shopping,\n \"shopping-cart\": $fa-var-shopping-cart,\n \"vials\": $fa-var-vials,\n \"plug-circle-plus\": $fa-var-plug-circle-plus,\n \"place-of-worship\": $fa-var-place-of-worship,\n \"grip-vertical\": $fa-var-grip-vertical,\n \"hexagon-nodes\": $fa-var-hexagon-nodes,\n \"arrow-turn-up\": $fa-var-arrow-turn-up,\n \"level-up\": $fa-var-level-up,\n \"u\": $fa-var-u,\n \"square-root-variable\": $fa-var-square-root-variable,\n \"square-root-alt\": $fa-var-square-root-alt,\n \"clock\": $fa-var-clock,\n \"clock-four\": $fa-var-clock-four,\n \"backward-step\": $fa-var-backward-step,\n \"step-backward\": $fa-var-step-backward,\n \"pallet\": $fa-var-pallet,\n \"faucet\": $fa-var-faucet,\n \"baseball-bat-ball\": $fa-var-baseball-bat-ball,\n \"s\": $fa-var-s,\n \"timeline\": $fa-var-timeline,\n \"keyboard\": $fa-var-keyboard,\n \"caret-down\": $fa-var-caret-down,\n \"house-chimney-medical\": $fa-var-house-chimney-medical,\n \"clinic-medical\": $fa-var-clinic-medical,\n \"temperature-three-quarters\": $fa-var-temperature-three-quarters,\n \"temperature-3\": $fa-var-temperature-3,\n \"thermometer-3\": $fa-var-thermometer-3,\n \"thermometer-three-quarters\": $fa-var-thermometer-three-quarters,\n \"mobile-screen\": $fa-var-mobile-screen,\n \"mobile-android-alt\": $fa-var-mobile-android-alt,\n \"plane-up\": $fa-var-plane-up,\n \"piggy-bank\": $fa-var-piggy-bank,\n \"battery-half\": $fa-var-battery-half,\n \"battery-3\": $fa-var-battery-3,\n \"mountain-city\": $fa-var-mountain-city,\n \"coins\": $fa-var-coins,\n \"khanda\": $fa-var-khanda,\n \"sliders\": $fa-var-sliders,\n \"sliders-h\": $fa-var-sliders-h,\n \"folder-tree\": $fa-var-folder-tree,\n \"network-wired\": $fa-var-network-wired,\n \"map-pin\": $fa-var-map-pin,\n \"hamsa\": $fa-var-hamsa,\n \"cent-sign\": $fa-var-cent-sign,\n \"flask\": $fa-var-flask,\n \"person-pregnant\": $fa-var-person-pregnant,\n \"wand-sparkles\": $fa-var-wand-sparkles,\n \"ellipsis-vertical\": $fa-var-ellipsis-vertical,\n \"ellipsis-v\": $fa-var-ellipsis-v,\n \"ticket\": $fa-var-ticket,\n \"power-off\": $fa-var-power-off,\n \"right-long\": $fa-var-right-long,\n \"long-arrow-alt-right\": $fa-var-long-arrow-alt-right,\n \"flag-usa\": $fa-var-flag-usa,\n \"laptop-file\": $fa-var-laptop-file,\n \"tty\": $fa-var-tty,\n \"teletype\": $fa-var-teletype,\n \"diagram-next\": $fa-var-diagram-next,\n \"person-rifle\": $fa-var-person-rifle,\n \"house-medical-circle-exclamation\": $fa-var-house-medical-circle-exclamation,\n \"closed-captioning\": $fa-var-closed-captioning,\n \"person-hiking\": $fa-var-person-hiking,\n \"hiking\": $fa-var-hiking,\n \"venus-double\": $fa-var-venus-double,\n \"images\": $fa-var-images,\n \"calculator\": $fa-var-calculator,\n \"people-pulling\": $fa-var-people-pulling,\n \"n\": $fa-var-n,\n \"cable-car\": $fa-var-cable-car,\n \"tram\": $fa-var-tram,\n \"cloud-rain\": $fa-var-cloud-rain,\n \"building-circle-xmark\": $fa-var-building-circle-xmark,\n \"ship\": $fa-var-ship,\n \"arrows-down-to-line\": $fa-var-arrows-down-to-line,\n \"download\": $fa-var-download,\n \"face-grin\": $fa-var-face-grin,\n \"grin\": $fa-var-grin,\n \"delete-left\": $fa-var-delete-left,\n \"backspace\": $fa-var-backspace,\n \"eye-dropper\": $fa-var-eye-dropper,\n \"eye-dropper-empty\": $fa-var-eye-dropper-empty,\n \"eyedropper\": $fa-var-eyedropper,\n \"file-circle-check\": $fa-var-file-circle-check,\n \"forward\": $fa-var-forward,\n \"mobile\": $fa-var-mobile,\n \"mobile-android\": $fa-var-mobile-android,\n \"mobile-phone\": $fa-var-mobile-phone,\n \"face-meh\": $fa-var-face-meh,\n \"meh\": $fa-var-meh,\n \"align-center\": $fa-var-align-center,\n \"book-skull\": $fa-var-book-skull,\n \"book-dead\": $fa-var-book-dead,\n \"id-card\": $fa-var-id-card,\n \"drivers-license\": $fa-var-drivers-license,\n \"outdent\": $fa-var-outdent,\n \"dedent\": $fa-var-dedent,\n \"heart-circle-exclamation\": $fa-var-heart-circle-exclamation,\n \"house\": $fa-var-house,\n \"home\": $fa-var-home,\n \"home-alt\": $fa-var-home-alt,\n \"home-lg-alt\": $fa-var-home-lg-alt,\n \"calendar-week\": $fa-var-calendar-week,\n \"laptop-medical\": $fa-var-laptop-medical,\n \"b\": $fa-var-b,\n \"file-medical\": $fa-var-file-medical,\n \"dice-one\": $fa-var-dice-one,\n \"kiwi-bird\": $fa-var-kiwi-bird,\n \"arrow-right-arrow-left\": $fa-var-arrow-right-arrow-left,\n \"exchange\": $fa-var-exchange,\n \"rotate-right\": $fa-var-rotate-right,\n \"redo-alt\": $fa-var-redo-alt,\n \"rotate-forward\": $fa-var-rotate-forward,\n \"utensils\": $fa-var-utensils,\n \"cutlery\": $fa-var-cutlery,\n \"arrow-up-wide-short\": $fa-var-arrow-up-wide-short,\n \"sort-amount-up\": $fa-var-sort-amount-up,\n \"mill-sign\": $fa-var-mill-sign,\n \"bowl-rice\": $fa-var-bowl-rice,\n \"skull\": $fa-var-skull,\n \"tower-broadcast\": $fa-var-tower-broadcast,\n \"broadcast-tower\": $fa-var-broadcast-tower,\n \"truck-pickup\": $fa-var-truck-pickup,\n \"up-long\": $fa-var-up-long,\n \"long-arrow-alt-up\": $fa-var-long-arrow-alt-up,\n \"stop\": $fa-var-stop,\n \"code-merge\": $fa-var-code-merge,\n \"upload\": $fa-var-upload,\n \"hurricane\": $fa-var-hurricane,\n \"mound\": $fa-var-mound,\n \"toilet-portable\": $fa-var-toilet-portable,\n \"compact-disc\": $fa-var-compact-disc,\n \"file-arrow-down\": $fa-var-file-arrow-down,\n \"file-download\": $fa-var-file-download,\n \"caravan\": $fa-var-caravan,\n \"shield-cat\": $fa-var-shield-cat,\n \"bolt\": $fa-var-bolt,\n \"zap\": $fa-var-zap,\n \"glass-water\": $fa-var-glass-water,\n \"oil-well\": $fa-var-oil-well,\n \"vault\": $fa-var-vault,\n \"mars\": $fa-var-mars,\n \"toilet\": $fa-var-toilet,\n \"plane-circle-xmark\": $fa-var-plane-circle-xmark,\n \"yen-sign\": $fa-var-yen-sign,\n \"cny\": $fa-var-cny,\n \"jpy\": $fa-var-jpy,\n \"rmb\": $fa-var-rmb,\n \"yen\": $fa-var-yen,\n \"ruble-sign\": $fa-var-ruble-sign,\n \"rouble\": $fa-var-rouble,\n \"rub\": $fa-var-rub,\n \"ruble\": $fa-var-ruble,\n \"sun\": $fa-var-sun,\n \"guitar\": $fa-var-guitar,\n \"face-laugh-wink\": $fa-var-face-laugh-wink,\n \"laugh-wink\": $fa-var-laugh-wink,\n \"horse-head\": $fa-var-horse-head,\n \"bore-hole\": $fa-var-bore-hole,\n \"industry\": $fa-var-industry,\n \"circle-down\": $fa-var-circle-down,\n \"arrow-alt-circle-down\": $fa-var-arrow-alt-circle-down,\n \"arrows-turn-to-dots\": $fa-var-arrows-turn-to-dots,\n \"florin-sign\": $fa-var-florin-sign,\n \"arrow-down-short-wide\": $fa-var-arrow-down-short-wide,\n \"sort-amount-desc\": $fa-var-sort-amount-desc,\n \"sort-amount-down-alt\": $fa-var-sort-amount-down-alt,\n \"less-than\": $fa-var-less-than,\n \"angle-down\": $fa-var-angle-down,\n \"car-tunnel\": $fa-var-car-tunnel,\n \"head-side-cough\": $fa-var-head-side-cough,\n \"grip-lines\": $fa-var-grip-lines,\n \"thumbs-down\": $fa-var-thumbs-down,\n \"user-lock\": $fa-var-user-lock,\n \"arrow-right-long\": $fa-var-arrow-right-long,\n \"long-arrow-right\": $fa-var-long-arrow-right,\n \"anchor-circle-xmark\": $fa-var-anchor-circle-xmark,\n \"ellipsis\": $fa-var-ellipsis,\n \"ellipsis-h\": $fa-var-ellipsis-h,\n \"chess-pawn\": $fa-var-chess-pawn,\n \"kit-medical\": $fa-var-kit-medical,\n \"first-aid\": $fa-var-first-aid,\n \"person-through-window\": $fa-var-person-through-window,\n \"toolbox\": $fa-var-toolbox,\n \"hands-holding-circle\": $fa-var-hands-holding-circle,\n \"bug\": $fa-var-bug,\n \"credit-card\": $fa-var-credit-card,\n \"credit-card-alt\": $fa-var-credit-card-alt,\n \"car\": $fa-var-car,\n \"automobile\": $fa-var-automobile,\n \"hand-holding-hand\": $fa-var-hand-holding-hand,\n \"book-open-reader\": $fa-var-book-open-reader,\n \"book-reader\": $fa-var-book-reader,\n \"mountain-sun\": $fa-var-mountain-sun,\n \"arrows-left-right-to-line\": $fa-var-arrows-left-right-to-line,\n \"dice-d20\": $fa-var-dice-d20,\n \"truck-droplet\": $fa-var-truck-droplet,\n \"file-circle-xmark\": $fa-var-file-circle-xmark,\n \"temperature-arrow-up\": $fa-var-temperature-arrow-up,\n \"temperature-up\": $fa-var-temperature-up,\n \"medal\": $fa-var-medal,\n \"bed\": $fa-var-bed,\n \"square-h\": $fa-var-square-h,\n \"h-square\": $fa-var-h-square,\n \"podcast\": $fa-var-podcast,\n \"temperature-full\": $fa-var-temperature-full,\n \"temperature-4\": $fa-var-temperature-4,\n \"thermometer-4\": $fa-var-thermometer-4,\n \"thermometer-full\": $fa-var-thermometer-full,\n \"bell\": $fa-var-bell,\n \"superscript\": $fa-var-superscript,\n \"plug-circle-xmark\": $fa-var-plug-circle-xmark,\n \"star-of-life\": $fa-var-star-of-life,\n \"phone-slash\": $fa-var-phone-slash,\n \"paint-roller\": $fa-var-paint-roller,\n \"handshake-angle\": $fa-var-handshake-angle,\n \"hands-helping\": $fa-var-hands-helping,\n \"location-dot\": $fa-var-location-dot,\n \"map-marker-alt\": $fa-var-map-marker-alt,\n \"file\": $fa-var-file,\n \"greater-than\": $fa-var-greater-than,\n \"person-swimming\": $fa-var-person-swimming,\n \"swimmer\": $fa-var-swimmer,\n \"arrow-down\": $fa-var-arrow-down,\n \"droplet\": $fa-var-droplet,\n \"tint\": $fa-var-tint,\n \"eraser\": $fa-var-eraser,\n \"earth-americas\": $fa-var-earth-americas,\n \"earth\": $fa-var-earth,\n \"earth-america\": $fa-var-earth-america,\n \"globe-americas\": $fa-var-globe-americas,\n \"person-burst\": $fa-var-person-burst,\n \"dove\": $fa-var-dove,\n \"battery-empty\": $fa-var-battery-empty,\n \"battery-0\": $fa-var-battery-0,\n \"socks\": $fa-var-socks,\n \"inbox\": $fa-var-inbox,\n \"section\": $fa-var-section,\n \"gauge-high\": $fa-var-gauge-high,\n \"tachometer-alt\": $fa-var-tachometer-alt,\n \"tachometer-alt-fast\": $fa-var-tachometer-alt-fast,\n \"envelope-open-text\": $fa-var-envelope-open-text,\n \"hospital\": $fa-var-hospital,\n \"hospital-alt\": $fa-var-hospital-alt,\n \"hospital-wide\": $fa-var-hospital-wide,\n \"wine-bottle\": $fa-var-wine-bottle,\n \"chess-rook\": $fa-var-chess-rook,\n \"bars-staggered\": $fa-var-bars-staggered,\n \"reorder\": $fa-var-reorder,\n \"stream\": $fa-var-stream,\n \"dharmachakra\": $fa-var-dharmachakra,\n \"hotdog\": $fa-var-hotdog,\n \"person-walking-with-cane\": $fa-var-person-walking-with-cane,\n \"blind\": $fa-var-blind,\n \"drum\": $fa-var-drum,\n \"ice-cream\": $fa-var-ice-cream,\n \"heart-circle-bolt\": $fa-var-heart-circle-bolt,\n \"fax\": $fa-var-fax,\n \"paragraph\": $fa-var-paragraph,\n \"check-to-slot\": $fa-var-check-to-slot,\n \"vote-yea\": $fa-var-vote-yea,\n \"star-half\": $fa-var-star-half,\n \"boxes-stacked\": $fa-var-boxes-stacked,\n \"boxes\": $fa-var-boxes,\n \"boxes-alt\": $fa-var-boxes-alt,\n \"link\": $fa-var-link,\n \"chain\": $fa-var-chain,\n \"ear-listen\": $fa-var-ear-listen,\n \"assistive-listening-systems\": $fa-var-assistive-listening-systems,\n \"tree-city\": $fa-var-tree-city,\n \"play\": $fa-var-play,\n \"font\": $fa-var-font,\n \"table-cells-row-lock\": $fa-var-table-cells-row-lock,\n \"rupiah-sign\": $fa-var-rupiah-sign,\n \"magnifying-glass\": $fa-var-magnifying-glass,\n \"search\": $fa-var-search,\n \"table-tennis-paddle-ball\": $fa-var-table-tennis-paddle-ball,\n \"ping-pong-paddle-ball\": $fa-var-ping-pong-paddle-ball,\n \"table-tennis\": $fa-var-table-tennis,\n \"person-dots-from-line\": $fa-var-person-dots-from-line,\n \"diagnoses\": $fa-var-diagnoses,\n \"trash-can-arrow-up\": $fa-var-trash-can-arrow-up,\n \"trash-restore-alt\": $fa-var-trash-restore-alt,\n \"naira-sign\": $fa-var-naira-sign,\n \"cart-arrow-down\": $fa-var-cart-arrow-down,\n \"walkie-talkie\": $fa-var-walkie-talkie,\n \"file-pen\": $fa-var-file-pen,\n \"file-edit\": $fa-var-file-edit,\n \"receipt\": $fa-var-receipt,\n \"square-pen\": $fa-var-square-pen,\n \"pen-square\": $fa-var-pen-square,\n \"pencil-square\": $fa-var-pencil-square,\n \"suitcase-rolling\": $fa-var-suitcase-rolling,\n \"person-circle-exclamation\": $fa-var-person-circle-exclamation,\n \"chevron-down\": $fa-var-chevron-down,\n \"battery-full\": $fa-var-battery-full,\n \"battery\": $fa-var-battery,\n \"battery-5\": $fa-var-battery-5,\n \"skull-crossbones\": $fa-var-skull-crossbones,\n \"code-compare\": $fa-var-code-compare,\n \"list-ul\": $fa-var-list-ul,\n \"list-dots\": $fa-var-list-dots,\n \"school-lock\": $fa-var-school-lock,\n \"tower-cell\": $fa-var-tower-cell,\n \"down-long\": $fa-var-down-long,\n \"long-arrow-alt-down\": $fa-var-long-arrow-alt-down,\n \"ranking-star\": $fa-var-ranking-star,\n \"chess-king\": $fa-var-chess-king,\n \"person-harassing\": $fa-var-person-harassing,\n \"brazilian-real-sign\": $fa-var-brazilian-real-sign,\n \"landmark-dome\": $fa-var-landmark-dome,\n \"landmark-alt\": $fa-var-landmark-alt,\n \"arrow-up\": $fa-var-arrow-up,\n \"tv\": $fa-var-tv,\n \"television\": $fa-var-television,\n \"tv-alt\": $fa-var-tv-alt,\n \"shrimp\": $fa-var-shrimp,\n \"list-check\": $fa-var-list-check,\n \"tasks\": $fa-var-tasks,\n \"jug-detergent\": $fa-var-jug-detergent,\n \"circle-user\": $fa-var-circle-user,\n \"user-circle\": $fa-var-user-circle,\n \"user-shield\": $fa-var-user-shield,\n \"wind\": $fa-var-wind,\n \"car-burst\": $fa-var-car-burst,\n \"car-crash\": $fa-var-car-crash,\n \"y\": $fa-var-y,\n \"person-snowboarding\": $fa-var-person-snowboarding,\n \"snowboarding\": $fa-var-snowboarding,\n \"truck-fast\": $fa-var-truck-fast,\n \"shipping-fast\": $fa-var-shipping-fast,\n \"fish\": $fa-var-fish,\n \"user-graduate\": $fa-var-user-graduate,\n \"circle-half-stroke\": $fa-var-circle-half-stroke,\n \"adjust\": $fa-var-adjust,\n \"clapperboard\": $fa-var-clapperboard,\n \"circle-radiation\": $fa-var-circle-radiation,\n \"radiation-alt\": $fa-var-radiation-alt,\n \"baseball\": $fa-var-baseball,\n \"baseball-ball\": $fa-var-baseball-ball,\n \"jet-fighter-up\": $fa-var-jet-fighter-up,\n \"diagram-project\": $fa-var-diagram-project,\n \"project-diagram\": $fa-var-project-diagram,\n \"copy\": $fa-var-copy,\n \"volume-xmark\": $fa-var-volume-xmark,\n \"volume-mute\": $fa-var-volume-mute,\n \"volume-times\": $fa-var-volume-times,\n \"hand-sparkles\": $fa-var-hand-sparkles,\n \"grip\": $fa-var-grip,\n \"grip-horizontal\": $fa-var-grip-horizontal,\n \"share-from-square\": $fa-var-share-from-square,\n \"share-square\": $fa-var-share-square,\n \"child-combatant\": $fa-var-child-combatant,\n \"child-rifle\": $fa-var-child-rifle,\n \"gun\": $fa-var-gun,\n \"square-phone\": $fa-var-square-phone,\n \"phone-square\": $fa-var-phone-square,\n \"plus\": $fa-var-plus,\n \"add\": $fa-var-add,\n \"expand\": $fa-var-expand,\n \"computer\": $fa-var-computer,\n \"xmark\": $fa-var-xmark,\n \"close\": $fa-var-close,\n \"multiply\": $fa-var-multiply,\n \"remove\": $fa-var-remove,\n \"times\": $fa-var-times,\n \"arrows-up-down-left-right\": $fa-var-arrows-up-down-left-right,\n \"arrows\": $fa-var-arrows,\n \"chalkboard-user\": $fa-var-chalkboard-user,\n \"chalkboard-teacher\": $fa-var-chalkboard-teacher,\n \"peso-sign\": $fa-var-peso-sign,\n \"building-shield\": $fa-var-building-shield,\n \"baby\": $fa-var-baby,\n \"users-line\": $fa-var-users-line,\n \"quote-left\": $fa-var-quote-left,\n \"quote-left-alt\": $fa-var-quote-left-alt,\n \"tractor\": $fa-var-tractor,\n \"trash-arrow-up\": $fa-var-trash-arrow-up,\n \"trash-restore\": $fa-var-trash-restore,\n \"arrow-down-up-lock\": $fa-var-arrow-down-up-lock,\n \"lines-leaning\": $fa-var-lines-leaning,\n \"ruler-combined\": $fa-var-ruler-combined,\n \"copyright\": $fa-var-copyright,\n \"equals\": $fa-var-equals,\n \"blender\": $fa-var-blender,\n \"teeth\": $fa-var-teeth,\n \"shekel-sign\": $fa-var-shekel-sign,\n \"ils\": $fa-var-ils,\n \"shekel\": $fa-var-shekel,\n \"sheqel\": $fa-var-sheqel,\n \"sheqel-sign\": $fa-var-sheqel-sign,\n \"map\": $fa-var-map,\n \"rocket\": $fa-var-rocket,\n \"photo-film\": $fa-var-photo-film,\n \"photo-video\": $fa-var-photo-video,\n \"folder-minus\": $fa-var-folder-minus,\n \"hexagon-nodes-bolt\": $fa-var-hexagon-nodes-bolt,\n \"store\": $fa-var-store,\n \"arrow-trend-up\": $fa-var-arrow-trend-up,\n \"plug-circle-minus\": $fa-var-plug-circle-minus,\n \"sign-hanging\": $fa-var-sign-hanging,\n \"sign\": $fa-var-sign,\n \"bezier-curve\": $fa-var-bezier-curve,\n \"bell-slash\": $fa-var-bell-slash,\n \"tablet\": $fa-var-tablet,\n \"tablet-android\": $fa-var-tablet-android,\n \"school-flag\": $fa-var-school-flag,\n \"fill\": $fa-var-fill,\n \"angle-up\": $fa-var-angle-up,\n \"drumstick-bite\": $fa-var-drumstick-bite,\n \"holly-berry\": $fa-var-holly-berry,\n \"chevron-left\": $fa-var-chevron-left,\n \"bacteria\": $fa-var-bacteria,\n \"hand-lizard\": $fa-var-hand-lizard,\n \"notdef\": $fa-var-notdef,\n \"disease\": $fa-var-disease,\n \"briefcase-medical\": $fa-var-briefcase-medical,\n \"genderless\": $fa-var-genderless,\n \"chevron-right\": $fa-var-chevron-right,\n \"retweet\": $fa-var-retweet,\n \"car-rear\": $fa-var-car-rear,\n \"car-alt\": $fa-var-car-alt,\n \"pump-soap\": $fa-var-pump-soap,\n \"video-slash\": $fa-var-video-slash,\n \"battery-quarter\": $fa-var-battery-quarter,\n \"battery-2\": $fa-var-battery-2,\n \"radio\": $fa-var-radio,\n \"baby-carriage\": $fa-var-baby-carriage,\n \"carriage-baby\": $fa-var-carriage-baby,\n \"traffic-light\": $fa-var-traffic-light,\n \"thermometer\": $fa-var-thermometer,\n \"vr-cardboard\": $fa-var-vr-cardboard,\n \"hand-middle-finger\": $fa-var-hand-middle-finger,\n \"percent\": $fa-var-percent,\n \"percentage\": $fa-var-percentage,\n \"truck-moving\": $fa-var-truck-moving,\n \"glass-water-droplet\": $fa-var-glass-water-droplet,\n \"display\": $fa-var-display,\n \"face-smile\": $fa-var-face-smile,\n \"smile\": $fa-var-smile,\n \"thumbtack\": $fa-var-thumbtack,\n \"thumb-tack\": $fa-var-thumb-tack,\n \"trophy\": $fa-var-trophy,\n \"person-praying\": $fa-var-person-praying,\n \"pray\": $fa-var-pray,\n \"hammer\": $fa-var-hammer,\n \"hand-peace\": $fa-var-hand-peace,\n \"rotate\": $fa-var-rotate,\n \"sync-alt\": $fa-var-sync-alt,\n \"spinner\": $fa-var-spinner,\n \"robot\": $fa-var-robot,\n \"peace\": $fa-var-peace,\n \"gears\": $fa-var-gears,\n \"cogs\": $fa-var-cogs,\n \"warehouse\": $fa-var-warehouse,\n \"arrow-up-right-dots\": $fa-var-arrow-up-right-dots,\n \"splotch\": $fa-var-splotch,\n \"face-grin-hearts\": $fa-var-face-grin-hearts,\n \"grin-hearts\": $fa-var-grin-hearts,\n \"dice-four\": $fa-var-dice-four,\n \"sim-card\": $fa-var-sim-card,\n \"transgender\": $fa-var-transgender,\n \"transgender-alt\": $fa-var-transgender-alt,\n \"mercury\": $fa-var-mercury,\n \"arrow-turn-down\": $fa-var-arrow-turn-down,\n \"level-down\": $fa-var-level-down,\n \"person-falling-burst\": $fa-var-person-falling-burst,\n \"award\": $fa-var-award,\n \"ticket-simple\": $fa-var-ticket-simple,\n \"ticket-alt\": $fa-var-ticket-alt,\n \"building\": $fa-var-building,\n \"angles-left\": $fa-var-angles-left,\n \"angle-double-left\": $fa-var-angle-double-left,\n \"qrcode\": $fa-var-qrcode,\n \"clock-rotate-left\": $fa-var-clock-rotate-left,\n \"history\": $fa-var-history,\n \"face-grin-beam-sweat\": $fa-var-face-grin-beam-sweat,\n \"grin-beam-sweat\": $fa-var-grin-beam-sweat,\n \"file-export\": $fa-var-file-export,\n \"arrow-right-from-file\": $fa-var-arrow-right-from-file,\n \"shield\": $fa-var-shield,\n \"shield-blank\": $fa-var-shield-blank,\n \"arrow-up-short-wide\": $fa-var-arrow-up-short-wide,\n \"sort-amount-up-alt\": $fa-var-sort-amount-up-alt,\n \"comment-nodes\": $fa-var-comment-nodes,\n \"house-medical\": $fa-var-house-medical,\n \"golf-ball-tee\": $fa-var-golf-ball-tee,\n \"golf-ball\": $fa-var-golf-ball,\n \"circle-chevron-left\": $fa-var-circle-chevron-left,\n \"chevron-circle-left\": $fa-var-chevron-circle-left,\n \"house-chimney-window\": $fa-var-house-chimney-window,\n \"pen-nib\": $fa-var-pen-nib,\n \"tent-arrow-turn-left\": $fa-var-tent-arrow-turn-left,\n \"tents\": $fa-var-tents,\n \"wand-magic\": $fa-var-wand-magic,\n \"magic\": $fa-var-magic,\n \"dog\": $fa-var-dog,\n \"carrot\": $fa-var-carrot,\n \"moon\": $fa-var-moon,\n \"wine-glass-empty\": $fa-var-wine-glass-empty,\n \"wine-glass-alt\": $fa-var-wine-glass-alt,\n \"cheese\": $fa-var-cheese,\n \"yin-yang\": $fa-var-yin-yang,\n \"music\": $fa-var-music,\n \"code-commit\": $fa-var-code-commit,\n \"temperature-low\": $fa-var-temperature-low,\n \"person-biking\": $fa-var-person-biking,\n \"biking\": $fa-var-biking,\n \"broom\": $fa-var-broom,\n \"shield-heart\": $fa-var-shield-heart,\n \"gopuram\": $fa-var-gopuram,\n \"earth-oceania\": $fa-var-earth-oceania,\n \"globe-oceania\": $fa-var-globe-oceania,\n \"square-xmark\": $fa-var-square-xmark,\n \"times-square\": $fa-var-times-square,\n \"xmark-square\": $fa-var-xmark-square,\n \"hashtag\": $fa-var-hashtag,\n \"up-right-and-down-left-from-center\": $fa-var-up-right-and-down-left-from-center,\n \"expand-alt\": $fa-var-expand-alt,\n \"oil-can\": $fa-var-oil-can,\n \"t\": $fa-var-t,\n \"hippo\": $fa-var-hippo,\n \"chart-column\": $fa-var-chart-column,\n \"infinity\": $fa-var-infinity,\n \"vial-circle-check\": $fa-var-vial-circle-check,\n \"person-arrow-down-to-line\": $fa-var-person-arrow-down-to-line,\n \"voicemail\": $fa-var-voicemail,\n \"fan\": $fa-var-fan,\n \"person-walking-luggage\": $fa-var-person-walking-luggage,\n \"up-down\": $fa-var-up-down,\n \"arrows-alt-v\": $fa-var-arrows-alt-v,\n \"cloud-moon-rain\": $fa-var-cloud-moon-rain,\n \"calendar\": $fa-var-calendar,\n \"trailer\": $fa-var-trailer,\n \"bahai\": $fa-var-bahai,\n \"haykal\": $fa-var-haykal,\n \"sd-card\": $fa-var-sd-card,\n \"dragon\": $fa-var-dragon,\n \"shoe-prints\": $fa-var-shoe-prints,\n \"circle-plus\": $fa-var-circle-plus,\n \"plus-circle\": $fa-var-plus-circle,\n \"face-grin-tongue-wink\": $fa-var-face-grin-tongue-wink,\n \"grin-tongue-wink\": $fa-var-grin-tongue-wink,\n \"hand-holding\": $fa-var-hand-holding,\n \"plug-circle-exclamation\": $fa-var-plug-circle-exclamation,\n \"link-slash\": $fa-var-link-slash,\n \"chain-broken\": $fa-var-chain-broken,\n \"chain-slash\": $fa-var-chain-slash,\n \"unlink\": $fa-var-unlink,\n \"clone\": $fa-var-clone,\n \"person-walking-arrow-loop-left\": $fa-var-person-walking-arrow-loop-left,\n \"arrow-up-z-a\": $fa-var-arrow-up-z-a,\n \"sort-alpha-up-alt\": $fa-var-sort-alpha-up-alt,\n \"fire-flame-curved\": $fa-var-fire-flame-curved,\n \"fire-alt\": $fa-var-fire-alt,\n \"tornado\": $fa-var-tornado,\n \"file-circle-plus\": $fa-var-file-circle-plus,\n \"book-quran\": $fa-var-book-quran,\n \"quran\": $fa-var-quran,\n \"anchor\": $fa-var-anchor,\n \"border-all\": $fa-var-border-all,\n \"face-angry\": $fa-var-face-angry,\n \"angry\": $fa-var-angry,\n \"cookie-bite\": $fa-var-cookie-bite,\n \"arrow-trend-down\": $fa-var-arrow-trend-down,\n \"rss\": $fa-var-rss,\n \"feed\": $fa-var-feed,\n \"draw-polygon\": $fa-var-draw-polygon,\n \"scale-balanced\": $fa-var-scale-balanced,\n \"balance-scale\": $fa-var-balance-scale,\n \"gauge-simple-high\": $fa-var-gauge-simple-high,\n \"tachometer\": $fa-var-tachometer,\n \"tachometer-fast\": $fa-var-tachometer-fast,\n \"shower\": $fa-var-shower,\n \"desktop\": $fa-var-desktop,\n \"desktop-alt\": $fa-var-desktop-alt,\n \"m\": $fa-var-m,\n \"table-list\": $fa-var-table-list,\n \"th-list\": $fa-var-th-list,\n \"comment-sms\": $fa-var-comment-sms,\n \"sms\": $fa-var-sms,\n \"book\": $fa-var-book,\n \"user-plus\": $fa-var-user-plus,\n \"check\": $fa-var-check,\n \"battery-three-quarters\": $fa-var-battery-three-quarters,\n \"battery-4\": $fa-var-battery-4,\n \"house-circle-check\": $fa-var-house-circle-check,\n \"angle-left\": $fa-var-angle-left,\n \"diagram-successor\": $fa-var-diagram-successor,\n \"truck-arrow-right\": $fa-var-truck-arrow-right,\n \"arrows-split-up-and-left\": $fa-var-arrows-split-up-and-left,\n \"hand-fist\": $fa-var-hand-fist,\n \"fist-raised\": $fa-var-fist-raised,\n \"cloud-moon\": $fa-var-cloud-moon,\n \"briefcase\": $fa-var-briefcase,\n \"person-falling\": $fa-var-person-falling,\n \"image-portrait\": $fa-var-image-portrait,\n \"portrait\": $fa-var-portrait,\n \"user-tag\": $fa-var-user-tag,\n \"rug\": $fa-var-rug,\n \"earth-europe\": $fa-var-earth-europe,\n \"globe-europe\": $fa-var-globe-europe,\n \"cart-flatbed-suitcase\": $fa-var-cart-flatbed-suitcase,\n \"luggage-cart\": $fa-var-luggage-cart,\n \"rectangle-xmark\": $fa-var-rectangle-xmark,\n \"rectangle-times\": $fa-var-rectangle-times,\n \"times-rectangle\": $fa-var-times-rectangle,\n \"window-close\": $fa-var-window-close,\n \"baht-sign\": $fa-var-baht-sign,\n \"book-open\": $fa-var-book-open,\n \"book-journal-whills\": $fa-var-book-journal-whills,\n \"journal-whills\": $fa-var-journal-whills,\n \"handcuffs\": $fa-var-handcuffs,\n \"triangle-exclamation\": $fa-var-triangle-exclamation,\n \"exclamation-triangle\": $fa-var-exclamation-triangle,\n \"warning\": $fa-var-warning,\n \"database\": $fa-var-database,\n \"share\": $fa-var-share,\n \"mail-forward\": $fa-var-mail-forward,\n \"bottle-droplet\": $fa-var-bottle-droplet,\n \"mask-face\": $fa-var-mask-face,\n \"hill-rockslide\": $fa-var-hill-rockslide,\n \"right-left\": $fa-var-right-left,\n \"exchange-alt\": $fa-var-exchange-alt,\n \"paper-plane\": $fa-var-paper-plane,\n \"road-circle-exclamation\": $fa-var-road-circle-exclamation,\n \"dungeon\": $fa-var-dungeon,\n \"align-right\": $fa-var-align-right,\n \"money-bill-1-wave\": $fa-var-money-bill-1-wave,\n \"money-bill-wave-alt\": $fa-var-money-bill-wave-alt,\n \"life-ring\": $fa-var-life-ring,\n \"hands\": $fa-var-hands,\n \"sign-language\": $fa-var-sign-language,\n \"signing\": $fa-var-signing,\n \"calendar-day\": $fa-var-calendar-day,\n \"water-ladder\": $fa-var-water-ladder,\n \"ladder-water\": $fa-var-ladder-water,\n \"swimming-pool\": $fa-var-swimming-pool,\n \"arrows-up-down\": $fa-var-arrows-up-down,\n \"arrows-v\": $fa-var-arrows-v,\n \"face-grimace\": $fa-var-face-grimace,\n \"grimace\": $fa-var-grimace,\n \"wheelchair-move\": $fa-var-wheelchair-move,\n \"wheelchair-alt\": $fa-var-wheelchair-alt,\n \"turn-down\": $fa-var-turn-down,\n \"level-down-alt\": $fa-var-level-down-alt,\n \"person-walking-arrow-right\": $fa-var-person-walking-arrow-right,\n \"square-envelope\": $fa-var-square-envelope,\n \"envelope-square\": $fa-var-envelope-square,\n \"dice\": $fa-var-dice,\n \"bowling-ball\": $fa-var-bowling-ball,\n \"brain\": $fa-var-brain,\n \"bandage\": $fa-var-bandage,\n \"band-aid\": $fa-var-band-aid,\n \"calendar-minus\": $fa-var-calendar-minus,\n \"circle-xmark\": $fa-var-circle-xmark,\n \"times-circle\": $fa-var-times-circle,\n \"xmark-circle\": $fa-var-xmark-circle,\n \"gifts\": $fa-var-gifts,\n \"hotel\": $fa-var-hotel,\n \"earth-asia\": $fa-var-earth-asia,\n \"globe-asia\": $fa-var-globe-asia,\n \"id-card-clip\": $fa-var-id-card-clip,\n \"id-card-alt\": $fa-var-id-card-alt,\n \"magnifying-glass-plus\": $fa-var-magnifying-glass-plus,\n \"search-plus\": $fa-var-search-plus,\n \"thumbs-up\": $fa-var-thumbs-up,\n \"user-clock\": $fa-var-user-clock,\n \"hand-dots\": $fa-var-hand-dots,\n \"allergies\": $fa-var-allergies,\n \"file-invoice\": $fa-var-file-invoice,\n \"window-minimize\": $fa-var-window-minimize,\n \"mug-saucer\": $fa-var-mug-saucer,\n \"coffee\": $fa-var-coffee,\n \"brush\": $fa-var-brush,\n \"file-half-dashed\": $fa-var-file-half-dashed,\n \"mask\": $fa-var-mask,\n \"magnifying-glass-minus\": $fa-var-magnifying-glass-minus,\n \"search-minus\": $fa-var-search-minus,\n \"ruler-vertical\": $fa-var-ruler-vertical,\n \"user-large\": $fa-var-user-large,\n \"user-alt\": $fa-var-user-alt,\n \"train-tram\": $fa-var-train-tram,\n \"user-nurse\": $fa-var-user-nurse,\n \"syringe\": $fa-var-syringe,\n \"cloud-sun\": $fa-var-cloud-sun,\n \"stopwatch-20\": $fa-var-stopwatch-20,\n \"square-full\": $fa-var-square-full,\n \"magnet\": $fa-var-magnet,\n \"jar\": $fa-var-jar,\n \"note-sticky\": $fa-var-note-sticky,\n \"sticky-note\": $fa-var-sticky-note,\n \"bug-slash\": $fa-var-bug-slash,\n \"arrow-up-from-water-pump\": $fa-var-arrow-up-from-water-pump,\n \"bone\": $fa-var-bone,\n \"table-cells-row-unlock\": $fa-var-table-cells-row-unlock,\n \"user-injured\": $fa-var-user-injured,\n \"face-sad-tear\": $fa-var-face-sad-tear,\n \"sad-tear\": $fa-var-sad-tear,\n \"plane\": $fa-var-plane,\n \"tent-arrows-down\": $fa-var-tent-arrows-down,\n \"exclamation\": $fa-var-exclamation,\n \"arrows-spin\": $fa-var-arrows-spin,\n \"print\": $fa-var-print,\n \"turkish-lira-sign\": $fa-var-turkish-lira-sign,\n \"try\": $fa-var-try,\n \"turkish-lira\": $fa-var-turkish-lira,\n \"dollar-sign\": $fa-var-dollar-sign,\n \"dollar\": $fa-var-dollar,\n \"usd\": $fa-var-usd,\n \"x\": $fa-var-x,\n \"magnifying-glass-dollar\": $fa-var-magnifying-glass-dollar,\n \"search-dollar\": $fa-var-search-dollar,\n \"users-gear\": $fa-var-users-gear,\n \"users-cog\": $fa-var-users-cog,\n \"person-military-pointing\": $fa-var-person-military-pointing,\n \"building-columns\": $fa-var-building-columns,\n \"bank\": $fa-var-bank,\n \"institution\": $fa-var-institution,\n \"museum\": $fa-var-museum,\n \"university\": $fa-var-university,\n \"umbrella\": $fa-var-umbrella,\n \"trowel\": $fa-var-trowel,\n \"d\": $fa-var-d,\n \"stapler\": $fa-var-stapler,\n \"masks-theater\": $fa-var-masks-theater,\n \"theater-masks\": $fa-var-theater-masks,\n \"kip-sign\": $fa-var-kip-sign,\n \"hand-point-left\": $fa-var-hand-point-left,\n \"handshake-simple\": $fa-var-handshake-simple,\n \"handshake-alt\": $fa-var-handshake-alt,\n \"jet-fighter\": $fa-var-jet-fighter,\n \"fighter-jet\": $fa-var-fighter-jet,\n \"square-share-nodes\": $fa-var-square-share-nodes,\n \"share-alt-square\": $fa-var-share-alt-square,\n \"barcode\": $fa-var-barcode,\n \"plus-minus\": $fa-var-plus-minus,\n \"video\": $fa-var-video,\n \"video-camera\": $fa-var-video-camera,\n \"graduation-cap\": $fa-var-graduation-cap,\n \"mortar-board\": $fa-var-mortar-board,\n \"hand-holding-medical\": $fa-var-hand-holding-medical,\n \"person-circle-check\": $fa-var-person-circle-check,\n \"turn-up\": $fa-var-turn-up,\n \"level-up-alt\": $fa-var-level-up-alt,\n);\n\n$fa-brand-icons: (\n \"monero\": $fa-var-monero,\n \"hooli\": $fa-var-hooli,\n \"yelp\": $fa-var-yelp,\n \"cc-visa\": $fa-var-cc-visa,\n \"lastfm\": $fa-var-lastfm,\n \"shopware\": $fa-var-shopware,\n \"creative-commons-nc\": $fa-var-creative-commons-nc,\n \"aws\": $fa-var-aws,\n \"redhat\": $fa-var-redhat,\n \"yoast\": $fa-var-yoast,\n \"cloudflare\": $fa-var-cloudflare,\n \"ups\": $fa-var-ups,\n \"pixiv\": $fa-var-pixiv,\n \"wpexplorer\": $fa-var-wpexplorer,\n \"dyalog\": $fa-var-dyalog,\n \"bity\": $fa-var-bity,\n \"stackpath\": $fa-var-stackpath,\n \"buysellads\": $fa-var-buysellads,\n \"first-order\": $fa-var-first-order,\n \"modx\": $fa-var-modx,\n \"guilded\": $fa-var-guilded,\n \"vnv\": $fa-var-vnv,\n \"square-js\": $fa-var-square-js,\n \"js-square\": $fa-var-js-square,\n \"microsoft\": $fa-var-microsoft,\n \"qq\": $fa-var-qq,\n \"orcid\": $fa-var-orcid,\n \"java\": $fa-var-java,\n \"invision\": $fa-var-invision,\n \"creative-commons-pd-alt\": $fa-var-creative-commons-pd-alt,\n \"centercode\": $fa-var-centercode,\n \"glide-g\": $fa-var-glide-g,\n \"drupal\": $fa-var-drupal,\n \"jxl\": $fa-var-jxl,\n \"dart-lang\": $fa-var-dart-lang,\n \"hire-a-helper\": $fa-var-hire-a-helper,\n \"creative-commons-by\": $fa-var-creative-commons-by,\n \"unity\": $fa-var-unity,\n \"whmcs\": $fa-var-whmcs,\n \"rocketchat\": $fa-var-rocketchat,\n \"vk\": $fa-var-vk,\n \"untappd\": $fa-var-untappd,\n \"mailchimp\": $fa-var-mailchimp,\n \"css3-alt\": $fa-var-css3-alt,\n \"square-reddit\": $fa-var-square-reddit,\n \"reddit-square\": $fa-var-reddit-square,\n \"vimeo-v\": $fa-var-vimeo-v,\n \"contao\": $fa-var-contao,\n \"square-font-awesome\": $fa-var-square-font-awesome,\n \"deskpro\": $fa-var-deskpro,\n \"brave\": $fa-var-brave,\n \"sistrix\": $fa-var-sistrix,\n \"square-instagram\": $fa-var-square-instagram,\n \"instagram-square\": $fa-var-instagram-square,\n \"battle-net\": $fa-var-battle-net,\n \"the-red-yeti\": $fa-var-the-red-yeti,\n \"square-hacker-news\": $fa-var-square-hacker-news,\n \"hacker-news-square\": $fa-var-hacker-news-square,\n \"edge\": $fa-var-edge,\n \"threads\": $fa-var-threads,\n \"napster\": $fa-var-napster,\n \"square-snapchat\": $fa-var-square-snapchat,\n \"snapchat-square\": $fa-var-snapchat-square,\n \"google-plus-g\": $fa-var-google-plus-g,\n \"artstation\": $fa-var-artstation,\n \"markdown\": $fa-var-markdown,\n \"sourcetree\": $fa-var-sourcetree,\n \"google-plus\": $fa-var-google-plus,\n \"diaspora\": $fa-var-diaspora,\n \"foursquare\": $fa-var-foursquare,\n \"stack-overflow\": $fa-var-stack-overflow,\n \"github-alt\": $fa-var-github-alt,\n \"phoenix-squadron\": $fa-var-phoenix-squadron,\n \"pagelines\": $fa-var-pagelines,\n \"algolia\": $fa-var-algolia,\n \"red-river\": $fa-var-red-river,\n \"creative-commons-sa\": $fa-var-creative-commons-sa,\n \"safari\": $fa-var-safari,\n \"google\": $fa-var-google,\n \"square-font-awesome-stroke\": $fa-var-square-font-awesome-stroke,\n \"font-awesome-alt\": $fa-var-font-awesome-alt,\n \"atlassian\": $fa-var-atlassian,\n \"linkedin-in\": $fa-var-linkedin-in,\n \"digital-ocean\": $fa-var-digital-ocean,\n \"nimblr\": $fa-var-nimblr,\n \"chromecast\": $fa-var-chromecast,\n \"evernote\": $fa-var-evernote,\n \"hacker-news\": $fa-var-hacker-news,\n \"creative-commons-sampling\": $fa-var-creative-commons-sampling,\n \"adversal\": $fa-var-adversal,\n \"creative-commons\": $fa-var-creative-commons,\n \"watchman-monitoring\": $fa-var-watchman-monitoring,\n \"fonticons\": $fa-var-fonticons,\n \"weixin\": $fa-var-weixin,\n \"shirtsinbulk\": $fa-var-shirtsinbulk,\n \"codepen\": $fa-var-codepen,\n \"git-alt\": $fa-var-git-alt,\n \"lyft\": $fa-var-lyft,\n \"rev\": $fa-var-rev,\n \"windows\": $fa-var-windows,\n \"wizards-of-the-coast\": $fa-var-wizards-of-the-coast,\n \"square-viadeo\": $fa-var-square-viadeo,\n \"viadeo-square\": $fa-var-viadeo-square,\n \"meetup\": $fa-var-meetup,\n \"centos\": $fa-var-centos,\n \"adn\": $fa-var-adn,\n \"cloudsmith\": $fa-var-cloudsmith,\n \"opensuse\": $fa-var-opensuse,\n \"pied-piper-alt\": $fa-var-pied-piper-alt,\n \"square-dribbble\": $fa-var-square-dribbble,\n \"dribbble-square\": $fa-var-dribbble-square,\n \"codiepie\": $fa-var-codiepie,\n \"node\": $fa-var-node,\n \"mix\": $fa-var-mix,\n \"steam\": $fa-var-steam,\n \"cc-apple-pay\": $fa-var-cc-apple-pay,\n \"scribd\": $fa-var-scribd,\n \"debian\": $fa-var-debian,\n \"openid\": $fa-var-openid,\n \"instalod\": $fa-var-instalod,\n \"files-pinwheel\": $fa-var-files-pinwheel,\n \"expeditedssl\": $fa-var-expeditedssl,\n \"sellcast\": $fa-var-sellcast,\n \"square-twitter\": $fa-var-square-twitter,\n \"twitter-square\": $fa-var-twitter-square,\n \"r-project\": $fa-var-r-project,\n \"delicious\": $fa-var-delicious,\n \"freebsd\": $fa-var-freebsd,\n \"vuejs\": $fa-var-vuejs,\n \"accusoft\": $fa-var-accusoft,\n \"ioxhost\": $fa-var-ioxhost,\n \"fonticons-fi\": $fa-var-fonticons-fi,\n \"app-store\": $fa-var-app-store,\n \"cc-mastercard\": $fa-var-cc-mastercard,\n \"itunes-note\": $fa-var-itunes-note,\n \"golang\": $fa-var-golang,\n \"kickstarter\": $fa-var-kickstarter,\n \"square-kickstarter\": $fa-var-square-kickstarter,\n \"grav\": $fa-var-grav,\n \"weibo\": $fa-var-weibo,\n \"uncharted\": $fa-var-uncharted,\n \"firstdraft\": $fa-var-firstdraft,\n \"square-youtube\": $fa-var-square-youtube,\n \"youtube-square\": $fa-var-youtube-square,\n \"wikipedia-w\": $fa-var-wikipedia-w,\n \"wpressr\": $fa-var-wpressr,\n \"rendact\": $fa-var-rendact,\n \"angellist\": $fa-var-angellist,\n \"galactic-republic\": $fa-var-galactic-republic,\n \"nfc-directional\": $fa-var-nfc-directional,\n \"skype\": $fa-var-skype,\n \"joget\": $fa-var-joget,\n \"fedora\": $fa-var-fedora,\n \"stripe-s\": $fa-var-stripe-s,\n \"meta\": $fa-var-meta,\n \"laravel\": $fa-var-laravel,\n \"hotjar\": $fa-var-hotjar,\n \"bluetooth-b\": $fa-var-bluetooth-b,\n \"square-letterboxd\": $fa-var-square-letterboxd,\n \"sticker-mule\": $fa-var-sticker-mule,\n \"creative-commons-zero\": $fa-var-creative-commons-zero,\n \"hips\": $fa-var-hips,\n \"css\": $fa-var-css,\n \"behance\": $fa-var-behance,\n \"reddit\": $fa-var-reddit,\n \"discord\": $fa-var-discord,\n \"chrome\": $fa-var-chrome,\n \"app-store-ios\": $fa-var-app-store-ios,\n \"cc-discover\": $fa-var-cc-discover,\n \"wpbeginner\": $fa-var-wpbeginner,\n \"confluence\": $fa-var-confluence,\n \"shoelace\": $fa-var-shoelace,\n \"mdb\": $fa-var-mdb,\n \"dochub\": $fa-var-dochub,\n \"accessible-icon\": $fa-var-accessible-icon,\n \"ebay\": $fa-var-ebay,\n \"amazon\": $fa-var-amazon,\n \"unsplash\": $fa-var-unsplash,\n \"yarn\": $fa-var-yarn,\n \"square-steam\": $fa-var-square-steam,\n \"steam-square\": $fa-var-steam-square,\n \"500px\": $fa-var-500px,\n \"square-vimeo\": $fa-var-square-vimeo,\n \"vimeo-square\": $fa-var-vimeo-square,\n \"asymmetrik\": $fa-var-asymmetrik,\n \"font-awesome\": $fa-var-font-awesome,\n \"font-awesome-flag\": $fa-var-font-awesome-flag,\n \"font-awesome-logo-full\": $fa-var-font-awesome-logo-full,\n \"gratipay\": $fa-var-gratipay,\n \"apple\": $fa-var-apple,\n \"hive\": $fa-var-hive,\n \"gitkraken\": $fa-var-gitkraken,\n \"keybase\": $fa-var-keybase,\n \"apple-pay\": $fa-var-apple-pay,\n \"padlet\": $fa-var-padlet,\n \"amazon-pay\": $fa-var-amazon-pay,\n \"square-github\": $fa-var-square-github,\n \"github-square\": $fa-var-github-square,\n \"stumbleupon\": $fa-var-stumbleupon,\n \"fedex\": $fa-var-fedex,\n \"phoenix-framework\": $fa-var-phoenix-framework,\n \"shopify\": $fa-var-shopify,\n \"neos\": $fa-var-neos,\n \"square-threads\": $fa-var-square-threads,\n \"hackerrank\": $fa-var-hackerrank,\n \"researchgate\": $fa-var-researchgate,\n \"swift\": $fa-var-swift,\n \"angular\": $fa-var-angular,\n \"speakap\": $fa-var-speakap,\n \"angrycreative\": $fa-var-angrycreative,\n \"y-combinator\": $fa-var-y-combinator,\n \"empire\": $fa-var-empire,\n \"envira\": $fa-var-envira,\n \"google-scholar\": $fa-var-google-scholar,\n \"square-gitlab\": $fa-var-square-gitlab,\n \"gitlab-square\": $fa-var-gitlab-square,\n \"studiovinari\": $fa-var-studiovinari,\n \"pied-piper\": $fa-var-pied-piper,\n \"wordpress\": $fa-var-wordpress,\n \"product-hunt\": $fa-var-product-hunt,\n \"firefox\": $fa-var-firefox,\n \"linode\": $fa-var-linode,\n \"goodreads\": $fa-var-goodreads,\n \"square-odnoklassniki\": $fa-var-square-odnoklassniki,\n \"odnoklassniki-square\": $fa-var-odnoklassniki-square,\n \"jsfiddle\": $fa-var-jsfiddle,\n \"sith\": $fa-var-sith,\n \"themeisle\": $fa-var-themeisle,\n \"page4\": $fa-var-page4,\n \"hashnode\": $fa-var-hashnode,\n \"react\": $fa-var-react,\n \"cc-paypal\": $fa-var-cc-paypal,\n \"squarespace\": $fa-var-squarespace,\n \"cc-stripe\": $fa-var-cc-stripe,\n \"creative-commons-share\": $fa-var-creative-commons-share,\n \"bitcoin\": $fa-var-bitcoin,\n \"keycdn\": $fa-var-keycdn,\n \"opera\": $fa-var-opera,\n \"itch-io\": $fa-var-itch-io,\n \"umbraco\": $fa-var-umbraco,\n \"galactic-senate\": $fa-var-galactic-senate,\n \"ubuntu\": $fa-var-ubuntu,\n \"draft2digital\": $fa-var-draft2digital,\n \"stripe\": $fa-var-stripe,\n \"houzz\": $fa-var-houzz,\n \"gg\": $fa-var-gg,\n \"dhl\": $fa-var-dhl,\n \"square-pinterest\": $fa-var-square-pinterest,\n \"pinterest-square\": $fa-var-pinterest-square,\n \"xing\": $fa-var-xing,\n \"blackberry\": $fa-var-blackberry,\n \"creative-commons-pd\": $fa-var-creative-commons-pd,\n \"playstation\": $fa-var-playstation,\n \"quinscape\": $fa-var-quinscape,\n \"less\": $fa-var-less,\n \"blogger-b\": $fa-var-blogger-b,\n \"opencart\": $fa-var-opencart,\n \"vine\": $fa-var-vine,\n \"signal-messenger\": $fa-var-signal-messenger,\n \"paypal\": $fa-var-paypal,\n \"gitlab\": $fa-var-gitlab,\n \"typo3\": $fa-var-typo3,\n \"reddit-alien\": $fa-var-reddit-alien,\n \"yahoo\": $fa-var-yahoo,\n \"dailymotion\": $fa-var-dailymotion,\n \"affiliatetheme\": $fa-var-affiliatetheme,\n \"pied-piper-pp\": $fa-var-pied-piper-pp,\n \"bootstrap\": $fa-var-bootstrap,\n \"odnoklassniki\": $fa-var-odnoklassniki,\n \"nfc-symbol\": $fa-var-nfc-symbol,\n \"mintbit\": $fa-var-mintbit,\n \"ethereum\": $fa-var-ethereum,\n \"speaker-deck\": $fa-var-speaker-deck,\n \"creative-commons-nc-eu\": $fa-var-creative-commons-nc-eu,\n \"patreon\": $fa-var-patreon,\n \"avianex\": $fa-var-avianex,\n \"ello\": $fa-var-ello,\n \"gofore\": $fa-var-gofore,\n \"bimobject\": $fa-var-bimobject,\n \"brave-reverse\": $fa-var-brave-reverse,\n \"facebook-f\": $fa-var-facebook-f,\n \"square-google-plus\": $fa-var-square-google-plus,\n \"google-plus-square\": $fa-var-google-plus-square,\n \"web-awesome\": $fa-var-web-awesome,\n \"mandalorian\": $fa-var-mandalorian,\n \"first-order-alt\": $fa-var-first-order-alt,\n \"osi\": $fa-var-osi,\n \"google-wallet\": $fa-var-google-wallet,\n \"d-and-d-beyond\": $fa-var-d-and-d-beyond,\n \"periscope\": $fa-var-periscope,\n \"fulcrum\": $fa-var-fulcrum,\n \"cloudscale\": $fa-var-cloudscale,\n \"forumbee\": $fa-var-forumbee,\n \"mizuni\": $fa-var-mizuni,\n \"schlix\": $fa-var-schlix,\n \"square-xing\": $fa-var-square-xing,\n \"xing-square\": $fa-var-xing-square,\n \"bandcamp\": $fa-var-bandcamp,\n \"wpforms\": $fa-var-wpforms,\n \"cloudversify\": $fa-var-cloudversify,\n \"usps\": $fa-var-usps,\n \"megaport\": $fa-var-megaport,\n \"magento\": $fa-var-magento,\n \"spotify\": $fa-var-spotify,\n \"optin-monster\": $fa-var-optin-monster,\n \"fly\": $fa-var-fly,\n \"square-bluesky\": $fa-var-square-bluesky,\n \"aviato\": $fa-var-aviato,\n \"itunes\": $fa-var-itunes,\n \"cuttlefish\": $fa-var-cuttlefish,\n \"blogger\": $fa-var-blogger,\n \"flickr\": $fa-var-flickr,\n \"viber\": $fa-var-viber,\n \"soundcloud\": $fa-var-soundcloud,\n \"digg\": $fa-var-digg,\n \"tencent-weibo\": $fa-var-tencent-weibo,\n \"letterboxd\": $fa-var-letterboxd,\n \"symfony\": $fa-var-symfony,\n \"maxcdn\": $fa-var-maxcdn,\n \"etsy\": $fa-var-etsy,\n \"facebook-messenger\": $fa-var-facebook-messenger,\n \"audible\": $fa-var-audible,\n \"think-peaks\": $fa-var-think-peaks,\n \"bilibili\": $fa-var-bilibili,\n \"erlang\": $fa-var-erlang,\n \"x-twitter\": $fa-var-x-twitter,\n \"cotton-bureau\": $fa-var-cotton-bureau,\n \"dashcube\": $fa-var-dashcube,\n \"42-group\": $fa-var-42-group,\n \"innosoft\": $fa-var-innosoft,\n \"stack-exchange\": $fa-var-stack-exchange,\n \"elementor\": $fa-var-elementor,\n \"square-pied-piper\": $fa-var-square-pied-piper,\n \"pied-piper-square\": $fa-var-pied-piper-square,\n \"creative-commons-nd\": $fa-var-creative-commons-nd,\n \"palfed\": $fa-var-palfed,\n \"superpowers\": $fa-var-superpowers,\n \"resolving\": $fa-var-resolving,\n \"xbox\": $fa-var-xbox,\n \"square-web-awesome-stroke\": $fa-var-square-web-awesome-stroke,\n \"searchengin\": $fa-var-searchengin,\n \"tiktok\": $fa-var-tiktok,\n \"square-facebook\": $fa-var-square-facebook,\n \"facebook-square\": $fa-var-facebook-square,\n \"renren\": $fa-var-renren,\n \"linux\": $fa-var-linux,\n \"glide\": $fa-var-glide,\n \"linkedin\": $fa-var-linkedin,\n \"hubspot\": $fa-var-hubspot,\n \"deploydog\": $fa-var-deploydog,\n \"twitch\": $fa-var-twitch,\n \"flutter\": $fa-var-flutter,\n \"ravelry\": $fa-var-ravelry,\n \"mixer\": $fa-var-mixer,\n \"square-lastfm\": $fa-var-square-lastfm,\n \"lastfm-square\": $fa-var-lastfm-square,\n \"vimeo\": $fa-var-vimeo,\n \"mendeley\": $fa-var-mendeley,\n \"uniregistry\": $fa-var-uniregistry,\n \"figma\": $fa-var-figma,\n \"creative-commons-remix\": $fa-var-creative-commons-remix,\n \"cc-amazon-pay\": $fa-var-cc-amazon-pay,\n \"dropbox\": $fa-var-dropbox,\n \"instagram\": $fa-var-instagram,\n \"cmplid\": $fa-var-cmplid,\n \"upwork\": $fa-var-upwork,\n \"facebook\": $fa-var-facebook,\n \"gripfire\": $fa-var-gripfire,\n \"jedi-order\": $fa-var-jedi-order,\n \"uikit\": $fa-var-uikit,\n \"fort-awesome-alt\": $fa-var-fort-awesome-alt,\n \"phabricator\": $fa-var-phabricator,\n \"ussunnah\": $fa-var-ussunnah,\n \"earlybirds\": $fa-var-earlybirds,\n \"trade-federation\": $fa-var-trade-federation,\n \"autoprefixer\": $fa-var-autoprefixer,\n \"whatsapp\": $fa-var-whatsapp,\n \"square-upwork\": $fa-var-square-upwork,\n \"slideshare\": $fa-var-slideshare,\n \"google-play\": $fa-var-google-play,\n \"viadeo\": $fa-var-viadeo,\n \"line\": $fa-var-line,\n \"google-drive\": $fa-var-google-drive,\n \"servicestack\": $fa-var-servicestack,\n \"simplybuilt\": $fa-var-simplybuilt,\n \"bitbucket\": $fa-var-bitbucket,\n \"imdb\": $fa-var-imdb,\n \"deezer\": $fa-var-deezer,\n \"raspberry-pi\": $fa-var-raspberry-pi,\n \"jira\": $fa-var-jira,\n \"docker\": $fa-var-docker,\n \"screenpal\": $fa-var-screenpal,\n \"bluetooth\": $fa-var-bluetooth,\n \"gitter\": $fa-var-gitter,\n \"d-and-d\": $fa-var-d-and-d,\n \"microblog\": $fa-var-microblog,\n \"cc-diners-club\": $fa-var-cc-diners-club,\n \"gg-circle\": $fa-var-gg-circle,\n \"pied-piper-hat\": $fa-var-pied-piper-hat,\n \"kickstarter-k\": $fa-var-kickstarter-k,\n \"yandex\": $fa-var-yandex,\n \"readme\": $fa-var-readme,\n \"html5\": $fa-var-html5,\n \"sellsy\": $fa-var-sellsy,\n \"square-web-awesome\": $fa-var-square-web-awesome,\n \"sass\": $fa-var-sass,\n \"wirsindhandwerk\": $fa-var-wirsindhandwerk,\n \"wsh\": $fa-var-wsh,\n \"buromobelexperte\": $fa-var-buromobelexperte,\n \"salesforce\": $fa-var-salesforce,\n \"octopus-deploy\": $fa-var-octopus-deploy,\n \"medapps\": $fa-var-medapps,\n \"ns8\": $fa-var-ns8,\n \"pinterest-p\": $fa-var-pinterest-p,\n \"apper\": $fa-var-apper,\n \"fort-awesome\": $fa-var-fort-awesome,\n \"waze\": $fa-var-waze,\n \"bluesky\": $fa-var-bluesky,\n \"cc-jcb\": $fa-var-cc-jcb,\n \"snapchat\": $fa-var-snapchat,\n \"snapchat-ghost\": $fa-var-snapchat-ghost,\n \"fantasy-flight-games\": $fa-var-fantasy-flight-games,\n \"rust\": $fa-var-rust,\n \"wix\": $fa-var-wix,\n \"square-behance\": $fa-var-square-behance,\n \"behance-square\": $fa-var-behance-square,\n \"supple\": $fa-var-supple,\n \"webflow\": $fa-var-webflow,\n \"rebel\": $fa-var-rebel,\n \"css3\": $fa-var-css3,\n \"staylinked\": $fa-var-staylinked,\n \"kaggle\": $fa-var-kaggle,\n \"space-awesome\": $fa-var-space-awesome,\n \"deviantart\": $fa-var-deviantart,\n \"cpanel\": $fa-var-cpanel,\n \"goodreads-g\": $fa-var-goodreads-g,\n \"square-git\": $fa-var-square-git,\n \"git-square\": $fa-var-git-square,\n \"square-tumblr\": $fa-var-square-tumblr,\n \"tumblr-square\": $fa-var-tumblr-square,\n \"trello\": $fa-var-trello,\n \"creative-commons-nc-jp\": $fa-var-creative-commons-nc-jp,\n \"get-pocket\": $fa-var-get-pocket,\n \"perbyte\": $fa-var-perbyte,\n \"grunt\": $fa-var-grunt,\n \"weebly\": $fa-var-weebly,\n \"connectdevelop\": $fa-var-connectdevelop,\n \"leanpub\": $fa-var-leanpub,\n \"black-tie\": $fa-var-black-tie,\n \"themeco\": $fa-var-themeco,\n \"python\": $fa-var-python,\n \"android\": $fa-var-android,\n \"bots\": $fa-var-bots,\n \"free-code-camp\": $fa-var-free-code-camp,\n \"hornbill\": $fa-var-hornbill,\n \"js\": $fa-var-js,\n \"ideal\": $fa-var-ideal,\n \"git\": $fa-var-git,\n \"dev\": $fa-var-dev,\n \"sketch\": $fa-var-sketch,\n \"yandex-international\": $fa-var-yandex-international,\n \"cc-amex\": $fa-var-cc-amex,\n \"uber\": $fa-var-uber,\n \"github\": $fa-var-github,\n \"php\": $fa-var-php,\n \"alipay\": $fa-var-alipay,\n \"youtube\": $fa-var-youtube,\n \"skyatlas\": $fa-var-skyatlas,\n \"firefox-browser\": $fa-var-firefox-browser,\n \"replyd\": $fa-var-replyd,\n \"suse\": $fa-var-suse,\n \"jenkins\": $fa-var-jenkins,\n \"twitter\": $fa-var-twitter,\n \"rockrms\": $fa-var-rockrms,\n \"pinterest\": $fa-var-pinterest,\n \"buffer\": $fa-var-buffer,\n \"npm\": $fa-var-npm,\n \"yammer\": $fa-var-yammer,\n \"btc\": $fa-var-btc,\n \"dribbble\": $fa-var-dribbble,\n \"stumbleupon-circle\": $fa-var-stumbleupon-circle,\n \"internet-explorer\": $fa-var-internet-explorer,\n \"stubber\": $fa-var-stubber,\n \"telegram\": $fa-var-telegram,\n \"telegram-plane\": $fa-var-telegram-plane,\n \"old-republic\": $fa-var-old-republic,\n \"odysee\": $fa-var-odysee,\n \"square-whatsapp\": $fa-var-square-whatsapp,\n \"whatsapp-square\": $fa-var-whatsapp-square,\n \"node-js\": $fa-var-node-js,\n \"edge-legacy\": $fa-var-edge-legacy,\n \"slack\": $fa-var-slack,\n \"slack-hash\": $fa-var-slack-hash,\n \"medrt\": $fa-var-medrt,\n \"usb\": $fa-var-usb,\n \"tumblr\": $fa-var-tumblr,\n \"vaadin\": $fa-var-vaadin,\n \"quora\": $fa-var-quora,\n \"square-x-twitter\": $fa-var-square-x-twitter,\n \"reacteurope\": $fa-var-reacteurope,\n \"medium\": $fa-var-medium,\n \"medium-m\": $fa-var-medium-m,\n \"amilia\": $fa-var-amilia,\n \"mixcloud\": $fa-var-mixcloud,\n \"flipboard\": $fa-var-flipboard,\n \"viacoin\": $fa-var-viacoin,\n \"critical-role\": $fa-var-critical-role,\n \"sitrox\": $fa-var-sitrox,\n \"discourse\": $fa-var-discourse,\n \"joomla\": $fa-var-joomla,\n \"mastodon\": $fa-var-mastodon,\n \"airbnb\": $fa-var-airbnb,\n \"wolf-pack-battalion\": $fa-var-wolf-pack-battalion,\n \"buy-n-large\": $fa-var-buy-n-large,\n \"gulp\": $fa-var-gulp,\n \"creative-commons-sampling-plus\": $fa-var-creative-commons-sampling-plus,\n \"strava\": $fa-var-strava,\n \"ember\": $fa-var-ember,\n \"canadian-maple-leaf\": $fa-var-canadian-maple-leaf,\n \"teamspeak\": $fa-var-teamspeak,\n \"pushed\": $fa-var-pushed,\n \"wordpress-simple\": $fa-var-wordpress-simple,\n \"nutritionix\": $fa-var-nutritionix,\n \"wodu\": $fa-var-wodu,\n \"google-pay\": $fa-var-google-pay,\n \"intercom\": $fa-var-intercom,\n \"zhihu\": $fa-var-zhihu,\n \"korvue\": $fa-var-korvue,\n \"pix\": $fa-var-pix,\n \"steam-symbol\": $fa-var-steam-symbol,\n);\n", + "/*!\n * Font Awesome Free 6.7.1 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n * Copyright 2024 Fonticons, Inc.\n */\n// V4 shims compile (Web Fonts-based)\n// -------------------------\n\n@import 'functions';\n@import 'variables';\n@import 'shims';\n", + "// functions\n// --------------------------\n\n// fa-content: convenience function used to set content property\n@function fa-content($fa-var) {\n @return unquote(\"\\\"#{ $fa-var }\\\"\");\n}\n\n// fa-divide: Originally obtained from the Bootstrap https://github.com/twbs/bootstrap\n//\n// Licensed under: The MIT License (MIT)\n//\n// Copyright (c) 2011-2021 Twitter, Inc.\n// Copyright (c) 2011-2021 The Bootstrap Authors\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n@function fa-divide($dividend, $divisor, $precision: 10) {\n $sign: if($dividend > 0 and $divisor > 0, 1, -1);\n $dividend: abs($dividend);\n $divisor: abs($divisor);\n $quotient: 0;\n $remainder: $dividend;\n @if $dividend == 0 {\n @return 0;\n }\n @if $divisor == 0 {\n @error \"Cannot divide by 0\";\n }\n @if $divisor == 1 {\n @return $dividend;\n }\n @while $remainder >= $divisor {\n $quotient: $quotient + 1;\n $remainder: $remainder - $divisor;\n }\n @if $remainder > 0 and $precision > 0 {\n $remainder: fa-divide($remainder * 10, $divisor, $precision - 1) * .1;\n }\n @return ($quotient + $remainder) * $sign;\n}\n", + "// variables\n// --------------------------\n\n$fa-css-prefix : fa !default;\n$fa-style : 900 !default;\n$fa-style-family : \"Font Awesome 6 Free\" !default;\n\n$fa-icon-property : --fa;\n$fa-duotone-icon-property : --fa--fa;\n\n$fa-display : inline-block !default;\n\n$fa-fw-width : fa-divide(20em, 16) !default;\n$fa-inverse : #fff !default;\n\n$fa-border-color : #eee !default;\n$fa-border-padding : .2em .25em .15em !default;\n$fa-border-radius : .1em !default;\n$fa-border-style : solid !default;\n$fa-border-width : .08em !default;\n\n$fa-size-scale-2xs : 10 !default;\n$fa-size-scale-xs : 12 !default;\n$fa-size-scale-sm : 14 !default;\n$fa-size-scale-base : 16 !default;\n$fa-size-scale-lg : 20 !default;\n$fa-size-scale-xl : 24 !default;\n$fa-size-scale-2xl : 32 !default;\n\n$fa-sizes: (\n \"2xs\" : $fa-size-scale-2xs,\n \"xs\" : $fa-size-scale-xs,\n \"sm\" : $fa-size-scale-sm,\n \"lg\" : $fa-size-scale-lg,\n \"xl\" : $fa-size-scale-xl,\n \"2xl\" : $fa-size-scale-2xl\n) !default;\n\n$fa-li-width : 2em !default;\n$fa-li-margin : $fa-li-width * fa-divide(5, 4) !default;\n\n$fa-pull-margin : .3em !default;\n\n$fa-primary-opacity : 1 !default;\n$fa-secondary-opacity : .4 !default;\n\n$fa-stack-vertical-align : middle !default;\n$fa-stack-width : ($fa-fw-width * 2) !default;\n$fa-stack-z-index : auto !default;\n\n$fa-font-display : block !default;\n$fa-font-path : \"../webfonts\" !default;\n\n$fa-var-0: \\30;\n$fa-var-1: \\31;\n$fa-var-2: \\32;\n$fa-var-3: \\33;\n$fa-var-4: \\34;\n$fa-var-5: \\35;\n$fa-var-6: \\36;\n$fa-var-7: \\37;\n$fa-var-8: \\38;\n$fa-var-9: \\39;\n$fa-var-fill-drip: \\f576;\n$fa-var-arrows-to-circle: \\e4bd;\n$fa-var-circle-chevron-right: \\f138;\n$fa-var-chevron-circle-right: \\f138;\n$fa-var-at: \\40;\n$fa-var-trash-can: \\f2ed;\n$fa-var-trash-alt: \\f2ed;\n$fa-var-text-height: \\f034;\n$fa-var-user-xmark: \\f235;\n$fa-var-user-times: \\f235;\n$fa-var-stethoscope: \\f0f1;\n$fa-var-message: \\f27a;\n$fa-var-comment-alt: \\f27a;\n$fa-var-info: \\f129;\n$fa-var-down-left-and-up-right-to-center: \\f422;\n$fa-var-compress-alt: \\f422;\n$fa-var-explosion: \\e4e9;\n$fa-var-file-lines: \\f15c;\n$fa-var-file-alt: \\f15c;\n$fa-var-file-text: \\f15c;\n$fa-var-wave-square: \\f83e;\n$fa-var-ring: \\f70b;\n$fa-var-building-un: \\e4d9;\n$fa-var-dice-three: \\f527;\n$fa-var-calendar-days: \\f073;\n$fa-var-calendar-alt: \\f073;\n$fa-var-anchor-circle-check: \\e4aa;\n$fa-var-building-circle-arrow-right: \\e4d1;\n$fa-var-volleyball: \\f45f;\n$fa-var-volleyball-ball: \\f45f;\n$fa-var-arrows-up-to-line: \\e4c2;\n$fa-var-sort-down: \\f0dd;\n$fa-var-sort-desc: \\f0dd;\n$fa-var-circle-minus: \\f056;\n$fa-var-minus-circle: \\f056;\n$fa-var-door-open: \\f52b;\n$fa-var-right-from-bracket: \\f2f5;\n$fa-var-sign-out-alt: \\f2f5;\n$fa-var-atom: \\f5d2;\n$fa-var-soap: \\e06e;\n$fa-var-icons: \\f86d;\n$fa-var-heart-music-camera-bolt: \\f86d;\n$fa-var-microphone-lines-slash: \\f539;\n$fa-var-microphone-alt-slash: \\f539;\n$fa-var-bridge-circle-check: \\e4c9;\n$fa-var-pump-medical: \\e06a;\n$fa-var-fingerprint: \\f577;\n$fa-var-hand-point-right: \\f0a4;\n$fa-var-magnifying-glass-location: \\f689;\n$fa-var-search-location: \\f689;\n$fa-var-forward-step: \\f051;\n$fa-var-step-forward: \\f051;\n$fa-var-face-smile-beam: \\f5b8;\n$fa-var-smile-beam: \\f5b8;\n$fa-var-flag-checkered: \\f11e;\n$fa-var-football: \\f44e;\n$fa-var-football-ball: \\f44e;\n$fa-var-school-circle-exclamation: \\e56c;\n$fa-var-crop: \\f125;\n$fa-var-angles-down: \\f103;\n$fa-var-angle-double-down: \\f103;\n$fa-var-users-rectangle: \\e594;\n$fa-var-people-roof: \\e537;\n$fa-var-people-line: \\e534;\n$fa-var-beer-mug-empty: \\f0fc;\n$fa-var-beer: \\f0fc;\n$fa-var-diagram-predecessor: \\e477;\n$fa-var-arrow-up-long: \\f176;\n$fa-var-long-arrow-up: \\f176;\n$fa-var-fire-flame-simple: \\f46a;\n$fa-var-burn: \\f46a;\n$fa-var-person: \\f183;\n$fa-var-male: \\f183;\n$fa-var-laptop: \\f109;\n$fa-var-file-csv: \\f6dd;\n$fa-var-menorah: \\f676;\n$fa-var-truck-plane: \\e58f;\n$fa-var-record-vinyl: \\f8d9;\n$fa-var-face-grin-stars: \\f587;\n$fa-var-grin-stars: \\f587;\n$fa-var-bong: \\f55c;\n$fa-var-spaghetti-monster-flying: \\f67b;\n$fa-var-pastafarianism: \\f67b;\n$fa-var-arrow-down-up-across-line: \\e4af;\n$fa-var-spoon: \\f2e5;\n$fa-var-utensil-spoon: \\f2e5;\n$fa-var-jar-wheat: \\e517;\n$fa-var-envelopes-bulk: \\f674;\n$fa-var-mail-bulk: \\f674;\n$fa-var-file-circle-exclamation: \\e4eb;\n$fa-var-circle-h: \\f47e;\n$fa-var-hospital-symbol: \\f47e;\n$fa-var-pager: \\f815;\n$fa-var-address-book: \\f2b9;\n$fa-var-contact-book: \\f2b9;\n$fa-var-strikethrough: \\f0cc;\n$fa-var-k: \\4b;\n$fa-var-landmark-flag: \\e51c;\n$fa-var-pencil: \\f303;\n$fa-var-pencil-alt: \\f303;\n$fa-var-backward: \\f04a;\n$fa-var-caret-right: \\f0da;\n$fa-var-comments: \\f086;\n$fa-var-paste: \\f0ea;\n$fa-var-file-clipboard: \\f0ea;\n$fa-var-code-pull-request: \\e13c;\n$fa-var-clipboard-list: \\f46d;\n$fa-var-truck-ramp-box: \\f4de;\n$fa-var-truck-loading: \\f4de;\n$fa-var-user-check: \\f4fc;\n$fa-var-vial-virus: \\e597;\n$fa-var-sheet-plastic: \\e571;\n$fa-var-blog: \\f781;\n$fa-var-user-ninja: \\f504;\n$fa-var-person-arrow-up-from-line: \\e539;\n$fa-var-scroll-torah: \\f6a0;\n$fa-var-torah: \\f6a0;\n$fa-var-broom-ball: \\f458;\n$fa-var-quidditch: \\f458;\n$fa-var-quidditch-broom-ball: \\f458;\n$fa-var-toggle-off: \\f204;\n$fa-var-box-archive: \\f187;\n$fa-var-archive: \\f187;\n$fa-var-person-drowning: \\e545;\n$fa-var-arrow-down-9-1: \\f886;\n$fa-var-sort-numeric-desc: \\f886;\n$fa-var-sort-numeric-down-alt: \\f886;\n$fa-var-face-grin-tongue-squint: \\f58a;\n$fa-var-grin-tongue-squint: \\f58a;\n$fa-var-spray-can: \\f5bd;\n$fa-var-truck-monster: \\f63b;\n$fa-var-w: \\57;\n$fa-var-earth-africa: \\f57c;\n$fa-var-globe-africa: \\f57c;\n$fa-var-rainbow: \\f75b;\n$fa-var-circle-notch: \\f1ce;\n$fa-var-tablet-screen-button: \\f3fa;\n$fa-var-tablet-alt: \\f3fa;\n$fa-var-paw: \\f1b0;\n$fa-var-cloud: \\f0c2;\n$fa-var-trowel-bricks: \\e58a;\n$fa-var-face-flushed: \\f579;\n$fa-var-flushed: \\f579;\n$fa-var-hospital-user: \\f80d;\n$fa-var-tent-arrow-left-right: \\e57f;\n$fa-var-gavel: \\f0e3;\n$fa-var-legal: \\f0e3;\n$fa-var-binoculars: \\f1e5;\n$fa-var-microphone-slash: \\f131;\n$fa-var-box-tissue: \\e05b;\n$fa-var-motorcycle: \\f21c;\n$fa-var-bell-concierge: \\f562;\n$fa-var-concierge-bell: \\f562;\n$fa-var-pen-ruler: \\f5ae;\n$fa-var-pencil-ruler: \\f5ae;\n$fa-var-people-arrows: \\e068;\n$fa-var-people-arrows-left-right: \\e068;\n$fa-var-mars-and-venus-burst: \\e523;\n$fa-var-square-caret-right: \\f152;\n$fa-var-caret-square-right: \\f152;\n$fa-var-scissors: \\f0c4;\n$fa-var-cut: \\f0c4;\n$fa-var-sun-plant-wilt: \\e57a;\n$fa-var-toilets-portable: \\e584;\n$fa-var-hockey-puck: \\f453;\n$fa-var-table: \\f0ce;\n$fa-var-magnifying-glass-arrow-right: \\e521;\n$fa-var-tachograph-digital: \\f566;\n$fa-var-digital-tachograph: \\f566;\n$fa-var-users-slash: \\e073;\n$fa-var-clover: \\e139;\n$fa-var-reply: \\f3e5;\n$fa-var-mail-reply: \\f3e5;\n$fa-var-star-and-crescent: \\f699;\n$fa-var-house-fire: \\e50c;\n$fa-var-square-minus: \\f146;\n$fa-var-minus-square: \\f146;\n$fa-var-helicopter: \\f533;\n$fa-var-compass: \\f14e;\n$fa-var-square-caret-down: \\f150;\n$fa-var-caret-square-down: \\f150;\n$fa-var-file-circle-question: \\e4ef;\n$fa-var-laptop-code: \\f5fc;\n$fa-var-swatchbook: \\f5c3;\n$fa-var-prescription-bottle: \\f485;\n$fa-var-bars: \\f0c9;\n$fa-var-navicon: \\f0c9;\n$fa-var-people-group: \\e533;\n$fa-var-hourglass-end: \\f253;\n$fa-var-hourglass-3: \\f253;\n$fa-var-heart-crack: \\f7a9;\n$fa-var-heart-broken: \\f7a9;\n$fa-var-square-up-right: \\f360;\n$fa-var-external-link-square-alt: \\f360;\n$fa-var-face-kiss-beam: \\f597;\n$fa-var-kiss-beam: \\f597;\n$fa-var-film: \\f008;\n$fa-var-ruler-horizontal: \\f547;\n$fa-var-people-robbery: \\e536;\n$fa-var-lightbulb: \\f0eb;\n$fa-var-caret-left: \\f0d9;\n$fa-var-circle-exclamation: \\f06a;\n$fa-var-exclamation-circle: \\f06a;\n$fa-var-school-circle-xmark: \\e56d;\n$fa-var-arrow-right-from-bracket: \\f08b;\n$fa-var-sign-out: \\f08b;\n$fa-var-circle-chevron-down: \\f13a;\n$fa-var-chevron-circle-down: \\f13a;\n$fa-var-unlock-keyhole: \\f13e;\n$fa-var-unlock-alt: \\f13e;\n$fa-var-cloud-showers-heavy: \\f740;\n$fa-var-headphones-simple: \\f58f;\n$fa-var-headphones-alt: \\f58f;\n$fa-var-sitemap: \\f0e8;\n$fa-var-circle-dollar-to-slot: \\f4b9;\n$fa-var-donate: \\f4b9;\n$fa-var-memory: \\f538;\n$fa-var-road-spikes: \\e568;\n$fa-var-fire-burner: \\e4f1;\n$fa-var-flag: \\f024;\n$fa-var-hanukiah: \\f6e6;\n$fa-var-feather: \\f52d;\n$fa-var-volume-low: \\f027;\n$fa-var-volume-down: \\f027;\n$fa-var-comment-slash: \\f4b3;\n$fa-var-cloud-sun-rain: \\f743;\n$fa-var-compress: \\f066;\n$fa-var-wheat-awn: \\e2cd;\n$fa-var-wheat-alt: \\e2cd;\n$fa-var-ankh: \\f644;\n$fa-var-hands-holding-child: \\e4fa;\n$fa-var-asterisk: \\2a;\n$fa-var-square-check: \\f14a;\n$fa-var-check-square: \\f14a;\n$fa-var-peseta-sign: \\e221;\n$fa-var-heading: \\f1dc;\n$fa-var-header: \\f1dc;\n$fa-var-ghost: \\f6e2;\n$fa-var-list: \\f03a;\n$fa-var-list-squares: \\f03a;\n$fa-var-square-phone-flip: \\f87b;\n$fa-var-phone-square-alt: \\f87b;\n$fa-var-cart-plus: \\f217;\n$fa-var-gamepad: \\f11b;\n$fa-var-circle-dot: \\f192;\n$fa-var-dot-circle: \\f192;\n$fa-var-face-dizzy: \\f567;\n$fa-var-dizzy: \\f567;\n$fa-var-egg: \\f7fb;\n$fa-var-house-medical-circle-xmark: \\e513;\n$fa-var-campground: \\f6bb;\n$fa-var-folder-plus: \\f65e;\n$fa-var-futbol: \\f1e3;\n$fa-var-futbol-ball: \\f1e3;\n$fa-var-soccer-ball: \\f1e3;\n$fa-var-paintbrush: \\f1fc;\n$fa-var-paint-brush: \\f1fc;\n$fa-var-lock: \\f023;\n$fa-var-gas-pump: \\f52f;\n$fa-var-hot-tub-person: \\f593;\n$fa-var-hot-tub: \\f593;\n$fa-var-map-location: \\f59f;\n$fa-var-map-marked: \\f59f;\n$fa-var-house-flood-water: \\e50e;\n$fa-var-tree: \\f1bb;\n$fa-var-bridge-lock: \\e4cc;\n$fa-var-sack-dollar: \\f81d;\n$fa-var-pen-to-square: \\f044;\n$fa-var-edit: \\f044;\n$fa-var-car-side: \\f5e4;\n$fa-var-share-nodes: \\f1e0;\n$fa-var-share-alt: \\f1e0;\n$fa-var-heart-circle-minus: \\e4ff;\n$fa-var-hourglass-half: \\f252;\n$fa-var-hourglass-2: \\f252;\n$fa-var-microscope: \\f610;\n$fa-var-sink: \\e06d;\n$fa-var-bag-shopping: \\f290;\n$fa-var-shopping-bag: \\f290;\n$fa-var-arrow-down-z-a: \\f881;\n$fa-var-sort-alpha-desc: \\f881;\n$fa-var-sort-alpha-down-alt: \\f881;\n$fa-var-mitten: \\f7b5;\n$fa-var-person-rays: \\e54d;\n$fa-var-users: \\f0c0;\n$fa-var-eye-slash: \\f070;\n$fa-var-flask-vial: \\e4f3;\n$fa-var-hand: \\f256;\n$fa-var-hand-paper: \\f256;\n$fa-var-om: \\f679;\n$fa-var-worm: \\e599;\n$fa-var-house-circle-xmark: \\e50b;\n$fa-var-plug: \\f1e6;\n$fa-var-chevron-up: \\f077;\n$fa-var-hand-spock: \\f259;\n$fa-var-stopwatch: \\f2f2;\n$fa-var-face-kiss: \\f596;\n$fa-var-kiss: \\f596;\n$fa-var-bridge-circle-xmark: \\e4cb;\n$fa-var-face-grin-tongue: \\f589;\n$fa-var-grin-tongue: \\f589;\n$fa-var-chess-bishop: \\f43a;\n$fa-var-face-grin-wink: \\f58c;\n$fa-var-grin-wink: \\f58c;\n$fa-var-ear-deaf: \\f2a4;\n$fa-var-deaf: \\f2a4;\n$fa-var-deafness: \\f2a4;\n$fa-var-hard-of-hearing: \\f2a4;\n$fa-var-road-circle-check: \\e564;\n$fa-var-dice-five: \\f523;\n$fa-var-square-rss: \\f143;\n$fa-var-rss-square: \\f143;\n$fa-var-land-mine-on: \\e51b;\n$fa-var-i-cursor: \\f246;\n$fa-var-stamp: \\f5bf;\n$fa-var-stairs: \\e289;\n$fa-var-i: \\49;\n$fa-var-hryvnia-sign: \\f6f2;\n$fa-var-hryvnia: \\f6f2;\n$fa-var-pills: \\f484;\n$fa-var-face-grin-wide: \\f581;\n$fa-var-grin-alt: \\f581;\n$fa-var-tooth: \\f5c9;\n$fa-var-v: \\56;\n$fa-var-bangladeshi-taka-sign: \\e2e6;\n$fa-var-bicycle: \\f206;\n$fa-var-staff-snake: \\e579;\n$fa-var-rod-asclepius: \\e579;\n$fa-var-rod-snake: \\e579;\n$fa-var-staff-aesculapius: \\e579;\n$fa-var-head-side-cough-slash: \\e062;\n$fa-var-truck-medical: \\f0f9;\n$fa-var-ambulance: \\f0f9;\n$fa-var-wheat-awn-circle-exclamation: \\e598;\n$fa-var-snowman: \\f7d0;\n$fa-var-mortar-pestle: \\f5a7;\n$fa-var-road-barrier: \\e562;\n$fa-var-school: \\f549;\n$fa-var-igloo: \\f7ae;\n$fa-var-joint: \\f595;\n$fa-var-angle-right: \\f105;\n$fa-var-horse: \\f6f0;\n$fa-var-q: \\51;\n$fa-var-g: \\47;\n$fa-var-notes-medical: \\f481;\n$fa-var-temperature-half: \\f2c9;\n$fa-var-temperature-2: \\f2c9;\n$fa-var-thermometer-2: \\f2c9;\n$fa-var-thermometer-half: \\f2c9;\n$fa-var-dong-sign: \\e169;\n$fa-var-capsules: \\f46b;\n$fa-var-poo-storm: \\f75a;\n$fa-var-poo-bolt: \\f75a;\n$fa-var-face-frown-open: \\f57a;\n$fa-var-frown-open: \\f57a;\n$fa-var-hand-point-up: \\f0a6;\n$fa-var-money-bill: \\f0d6;\n$fa-var-bookmark: \\f02e;\n$fa-var-align-justify: \\f039;\n$fa-var-umbrella-beach: \\f5ca;\n$fa-var-helmet-un: \\e503;\n$fa-var-bullseye: \\f140;\n$fa-var-bacon: \\f7e5;\n$fa-var-hand-point-down: \\f0a7;\n$fa-var-arrow-up-from-bracket: \\e09a;\n$fa-var-folder: \\f07b;\n$fa-var-folder-blank: \\f07b;\n$fa-var-file-waveform: \\f478;\n$fa-var-file-medical-alt: \\f478;\n$fa-var-radiation: \\f7b9;\n$fa-var-chart-simple: \\e473;\n$fa-var-mars-stroke: \\f229;\n$fa-var-vial: \\f492;\n$fa-var-gauge: \\f624;\n$fa-var-dashboard: \\f624;\n$fa-var-gauge-med: \\f624;\n$fa-var-tachometer-alt-average: \\f624;\n$fa-var-wand-magic-sparkles: \\e2ca;\n$fa-var-magic-wand-sparkles: \\e2ca;\n$fa-var-e: \\45;\n$fa-var-pen-clip: \\f305;\n$fa-var-pen-alt: \\f305;\n$fa-var-bridge-circle-exclamation: \\e4ca;\n$fa-var-user: \\f007;\n$fa-var-school-circle-check: \\e56b;\n$fa-var-dumpster: \\f793;\n$fa-var-van-shuttle: \\f5b6;\n$fa-var-shuttle-van: \\f5b6;\n$fa-var-building-user: \\e4da;\n$fa-var-square-caret-left: \\f191;\n$fa-var-caret-square-left: \\f191;\n$fa-var-highlighter: \\f591;\n$fa-var-key: \\f084;\n$fa-var-bullhorn: \\f0a1;\n$fa-var-globe: \\f0ac;\n$fa-var-synagogue: \\f69b;\n$fa-var-person-half-dress: \\e548;\n$fa-var-road-bridge: \\e563;\n$fa-var-location-arrow: \\f124;\n$fa-var-c: \\43;\n$fa-var-tablet-button: \\f10a;\n$fa-var-building-lock: \\e4d6;\n$fa-var-pizza-slice: \\f818;\n$fa-var-money-bill-wave: \\f53a;\n$fa-var-chart-area: \\f1fe;\n$fa-var-area-chart: \\f1fe;\n$fa-var-house-flag: \\e50d;\n$fa-var-person-circle-minus: \\e540;\n$fa-var-ban: \\f05e;\n$fa-var-cancel: \\f05e;\n$fa-var-camera-rotate: \\e0d8;\n$fa-var-spray-can-sparkles: \\f5d0;\n$fa-var-air-freshener: \\f5d0;\n$fa-var-star: \\f005;\n$fa-var-repeat: \\f363;\n$fa-var-cross: \\f654;\n$fa-var-box: \\f466;\n$fa-var-venus-mars: \\f228;\n$fa-var-arrow-pointer: \\f245;\n$fa-var-mouse-pointer: \\f245;\n$fa-var-maximize: \\f31e;\n$fa-var-expand-arrows-alt: \\f31e;\n$fa-var-charging-station: \\f5e7;\n$fa-var-shapes: \\f61f;\n$fa-var-triangle-circle-square: \\f61f;\n$fa-var-shuffle: \\f074;\n$fa-var-random: \\f074;\n$fa-var-person-running: \\f70c;\n$fa-var-running: \\f70c;\n$fa-var-mobile-retro: \\e527;\n$fa-var-grip-lines-vertical: \\f7a5;\n$fa-var-spider: \\f717;\n$fa-var-hands-bound: \\e4f9;\n$fa-var-file-invoice-dollar: \\f571;\n$fa-var-plane-circle-exclamation: \\e556;\n$fa-var-x-ray: \\f497;\n$fa-var-spell-check: \\f891;\n$fa-var-slash: \\f715;\n$fa-var-computer-mouse: \\f8cc;\n$fa-var-mouse: \\f8cc;\n$fa-var-arrow-right-to-bracket: \\f090;\n$fa-var-sign-in: \\f090;\n$fa-var-shop-slash: \\e070;\n$fa-var-store-alt-slash: \\e070;\n$fa-var-server: \\f233;\n$fa-var-virus-covid-slash: \\e4a9;\n$fa-var-shop-lock: \\e4a5;\n$fa-var-hourglass-start: \\f251;\n$fa-var-hourglass-1: \\f251;\n$fa-var-blender-phone: \\f6b6;\n$fa-var-building-wheat: \\e4db;\n$fa-var-person-breastfeeding: \\e53a;\n$fa-var-right-to-bracket: \\f2f6;\n$fa-var-sign-in-alt: \\f2f6;\n$fa-var-venus: \\f221;\n$fa-var-passport: \\f5ab;\n$fa-var-thumbtack-slash: \\e68f;\n$fa-var-thumb-tack-slash: \\e68f;\n$fa-var-heart-pulse: \\f21e;\n$fa-var-heartbeat: \\f21e;\n$fa-var-people-carry-box: \\f4ce;\n$fa-var-people-carry: \\f4ce;\n$fa-var-temperature-high: \\f769;\n$fa-var-microchip: \\f2db;\n$fa-var-crown: \\f521;\n$fa-var-weight-hanging: \\f5cd;\n$fa-var-xmarks-lines: \\e59a;\n$fa-var-file-prescription: \\f572;\n$fa-var-weight-scale: \\f496;\n$fa-var-weight: \\f496;\n$fa-var-user-group: \\f500;\n$fa-var-user-friends: \\f500;\n$fa-var-arrow-up-a-z: \\f15e;\n$fa-var-sort-alpha-up: \\f15e;\n$fa-var-chess-knight: \\f441;\n$fa-var-face-laugh-squint: \\f59b;\n$fa-var-laugh-squint: \\f59b;\n$fa-var-wheelchair: \\f193;\n$fa-var-circle-arrow-up: \\f0aa;\n$fa-var-arrow-circle-up: \\f0aa;\n$fa-var-toggle-on: \\f205;\n$fa-var-person-walking: \\f554;\n$fa-var-walking: \\f554;\n$fa-var-l: \\4c;\n$fa-var-fire: \\f06d;\n$fa-var-bed-pulse: \\f487;\n$fa-var-procedures: \\f487;\n$fa-var-shuttle-space: \\f197;\n$fa-var-space-shuttle: \\f197;\n$fa-var-face-laugh: \\f599;\n$fa-var-laugh: \\f599;\n$fa-var-folder-open: \\f07c;\n$fa-var-heart-circle-plus: \\e500;\n$fa-var-code-fork: \\e13b;\n$fa-var-city: \\f64f;\n$fa-var-microphone-lines: \\f3c9;\n$fa-var-microphone-alt: \\f3c9;\n$fa-var-pepper-hot: \\f816;\n$fa-var-unlock: \\f09c;\n$fa-var-colon-sign: \\e140;\n$fa-var-headset: \\f590;\n$fa-var-store-slash: \\e071;\n$fa-var-road-circle-xmark: \\e566;\n$fa-var-user-minus: \\f503;\n$fa-var-mars-stroke-up: \\f22a;\n$fa-var-mars-stroke-v: \\f22a;\n$fa-var-champagne-glasses: \\f79f;\n$fa-var-glass-cheers: \\f79f;\n$fa-var-clipboard: \\f328;\n$fa-var-house-circle-exclamation: \\e50a;\n$fa-var-file-arrow-up: \\f574;\n$fa-var-file-upload: \\f574;\n$fa-var-wifi: \\f1eb;\n$fa-var-wifi-3: \\f1eb;\n$fa-var-wifi-strong: \\f1eb;\n$fa-var-bath: \\f2cd;\n$fa-var-bathtub: \\f2cd;\n$fa-var-underline: \\f0cd;\n$fa-var-user-pen: \\f4ff;\n$fa-var-user-edit: \\f4ff;\n$fa-var-signature: \\f5b7;\n$fa-var-stroopwafel: \\f551;\n$fa-var-bold: \\f032;\n$fa-var-anchor-lock: \\e4ad;\n$fa-var-building-ngo: \\e4d7;\n$fa-var-manat-sign: \\e1d5;\n$fa-var-not-equal: \\f53e;\n$fa-var-border-top-left: \\f853;\n$fa-var-border-style: \\f853;\n$fa-var-map-location-dot: \\f5a0;\n$fa-var-map-marked-alt: \\f5a0;\n$fa-var-jedi: \\f669;\n$fa-var-square-poll-vertical: \\f681;\n$fa-var-poll: \\f681;\n$fa-var-mug-hot: \\f7b6;\n$fa-var-car-battery: \\f5df;\n$fa-var-battery-car: \\f5df;\n$fa-var-gift: \\f06b;\n$fa-var-dice-two: \\f528;\n$fa-var-chess-queen: \\f445;\n$fa-var-glasses: \\f530;\n$fa-var-chess-board: \\f43c;\n$fa-var-building-circle-check: \\e4d2;\n$fa-var-person-chalkboard: \\e53d;\n$fa-var-mars-stroke-right: \\f22b;\n$fa-var-mars-stroke-h: \\f22b;\n$fa-var-hand-back-fist: \\f255;\n$fa-var-hand-rock: \\f255;\n$fa-var-square-caret-up: \\f151;\n$fa-var-caret-square-up: \\f151;\n$fa-var-cloud-showers-water: \\e4e4;\n$fa-var-chart-bar: \\f080;\n$fa-var-bar-chart: \\f080;\n$fa-var-hands-bubbles: \\e05e;\n$fa-var-hands-wash: \\e05e;\n$fa-var-less-than-equal: \\f537;\n$fa-var-train: \\f238;\n$fa-var-eye-low-vision: \\f2a8;\n$fa-var-low-vision: \\f2a8;\n$fa-var-crow: \\f520;\n$fa-var-sailboat: \\e445;\n$fa-var-window-restore: \\f2d2;\n$fa-var-square-plus: \\f0fe;\n$fa-var-plus-square: \\f0fe;\n$fa-var-torii-gate: \\f6a1;\n$fa-var-frog: \\f52e;\n$fa-var-bucket: \\e4cf;\n$fa-var-image: \\f03e;\n$fa-var-microphone: \\f130;\n$fa-var-cow: \\f6c8;\n$fa-var-caret-up: \\f0d8;\n$fa-var-screwdriver: \\f54a;\n$fa-var-folder-closed: \\e185;\n$fa-var-house-tsunami: \\e515;\n$fa-var-square-nfi: \\e576;\n$fa-var-arrow-up-from-ground-water: \\e4b5;\n$fa-var-martini-glass: \\f57b;\n$fa-var-glass-martini-alt: \\f57b;\n$fa-var-square-binary: \\e69b;\n$fa-var-rotate-left: \\f2ea;\n$fa-var-rotate-back: \\f2ea;\n$fa-var-rotate-backward: \\f2ea;\n$fa-var-undo-alt: \\f2ea;\n$fa-var-table-columns: \\f0db;\n$fa-var-columns: \\f0db;\n$fa-var-lemon: \\f094;\n$fa-var-head-side-mask: \\e063;\n$fa-var-handshake: \\f2b5;\n$fa-var-gem: \\f3a5;\n$fa-var-dolly: \\f472;\n$fa-var-dolly-box: \\f472;\n$fa-var-smoking: \\f48d;\n$fa-var-minimize: \\f78c;\n$fa-var-compress-arrows-alt: \\f78c;\n$fa-var-monument: \\f5a6;\n$fa-var-snowplow: \\f7d2;\n$fa-var-angles-right: \\f101;\n$fa-var-angle-double-right: \\f101;\n$fa-var-cannabis: \\f55f;\n$fa-var-circle-play: \\f144;\n$fa-var-play-circle: \\f144;\n$fa-var-tablets: \\f490;\n$fa-var-ethernet: \\f796;\n$fa-var-euro-sign: \\f153;\n$fa-var-eur: \\f153;\n$fa-var-euro: \\f153;\n$fa-var-chair: \\f6c0;\n$fa-var-circle-check: \\f058;\n$fa-var-check-circle: \\f058;\n$fa-var-circle-stop: \\f28d;\n$fa-var-stop-circle: \\f28d;\n$fa-var-compass-drafting: \\f568;\n$fa-var-drafting-compass: \\f568;\n$fa-var-plate-wheat: \\e55a;\n$fa-var-icicles: \\f7ad;\n$fa-var-person-shelter: \\e54f;\n$fa-var-neuter: \\f22c;\n$fa-var-id-badge: \\f2c1;\n$fa-var-marker: \\f5a1;\n$fa-var-face-laugh-beam: \\f59a;\n$fa-var-laugh-beam: \\f59a;\n$fa-var-helicopter-symbol: \\e502;\n$fa-var-universal-access: \\f29a;\n$fa-var-circle-chevron-up: \\f139;\n$fa-var-chevron-circle-up: \\f139;\n$fa-var-lari-sign: \\e1c8;\n$fa-var-volcano: \\f770;\n$fa-var-person-walking-dashed-line-arrow-right: \\e553;\n$fa-var-sterling-sign: \\f154;\n$fa-var-gbp: \\f154;\n$fa-var-pound-sign: \\f154;\n$fa-var-viruses: \\e076;\n$fa-var-square-person-confined: \\e577;\n$fa-var-user-tie: \\f508;\n$fa-var-arrow-down-long: \\f175;\n$fa-var-long-arrow-down: \\f175;\n$fa-var-tent-arrow-down-to-line: \\e57e;\n$fa-var-certificate: \\f0a3;\n$fa-var-reply-all: \\f122;\n$fa-var-mail-reply-all: \\f122;\n$fa-var-suitcase: \\f0f2;\n$fa-var-person-skating: \\f7c5;\n$fa-var-skating: \\f7c5;\n$fa-var-filter-circle-dollar: \\f662;\n$fa-var-funnel-dollar: \\f662;\n$fa-var-camera-retro: \\f083;\n$fa-var-circle-arrow-down: \\f0ab;\n$fa-var-arrow-circle-down: \\f0ab;\n$fa-var-file-import: \\f56f;\n$fa-var-arrow-right-to-file: \\f56f;\n$fa-var-square-arrow-up-right: \\f14c;\n$fa-var-external-link-square: \\f14c;\n$fa-var-box-open: \\f49e;\n$fa-var-scroll: \\f70e;\n$fa-var-spa: \\f5bb;\n$fa-var-location-pin-lock: \\e51f;\n$fa-var-pause: \\f04c;\n$fa-var-hill-avalanche: \\e507;\n$fa-var-temperature-empty: \\f2cb;\n$fa-var-temperature-0: \\f2cb;\n$fa-var-thermometer-0: \\f2cb;\n$fa-var-thermometer-empty: \\f2cb;\n$fa-var-bomb: \\f1e2;\n$fa-var-registered: \\f25d;\n$fa-var-address-card: \\f2bb;\n$fa-var-contact-card: \\f2bb;\n$fa-var-vcard: \\f2bb;\n$fa-var-scale-unbalanced-flip: \\f516;\n$fa-var-balance-scale-right: \\f516;\n$fa-var-subscript: \\f12c;\n$fa-var-diamond-turn-right: \\f5eb;\n$fa-var-directions: \\f5eb;\n$fa-var-burst: \\e4dc;\n$fa-var-house-laptop: \\e066;\n$fa-var-laptop-house: \\e066;\n$fa-var-face-tired: \\f5c8;\n$fa-var-tired: \\f5c8;\n$fa-var-money-bills: \\e1f3;\n$fa-var-smog: \\f75f;\n$fa-var-crutch: \\f7f7;\n$fa-var-cloud-arrow-up: \\f0ee;\n$fa-var-cloud-upload: \\f0ee;\n$fa-var-cloud-upload-alt: \\f0ee;\n$fa-var-palette: \\f53f;\n$fa-var-arrows-turn-right: \\e4c0;\n$fa-var-vest: \\e085;\n$fa-var-ferry: \\e4ea;\n$fa-var-arrows-down-to-people: \\e4b9;\n$fa-var-seedling: \\f4d8;\n$fa-var-sprout: \\f4d8;\n$fa-var-left-right: \\f337;\n$fa-var-arrows-alt-h: \\f337;\n$fa-var-boxes-packing: \\e4c7;\n$fa-var-circle-arrow-left: \\f0a8;\n$fa-var-arrow-circle-left: \\f0a8;\n$fa-var-group-arrows-rotate: \\e4f6;\n$fa-var-bowl-food: \\e4c6;\n$fa-var-candy-cane: \\f786;\n$fa-var-arrow-down-wide-short: \\f160;\n$fa-var-sort-amount-asc: \\f160;\n$fa-var-sort-amount-down: \\f160;\n$fa-var-cloud-bolt: \\f76c;\n$fa-var-thunderstorm: \\f76c;\n$fa-var-text-slash: \\f87d;\n$fa-var-remove-format: \\f87d;\n$fa-var-face-smile-wink: \\f4da;\n$fa-var-smile-wink: \\f4da;\n$fa-var-file-word: \\f1c2;\n$fa-var-file-powerpoint: \\f1c4;\n$fa-var-arrows-left-right: \\f07e;\n$fa-var-arrows-h: \\f07e;\n$fa-var-house-lock: \\e510;\n$fa-var-cloud-arrow-down: \\f0ed;\n$fa-var-cloud-download: \\f0ed;\n$fa-var-cloud-download-alt: \\f0ed;\n$fa-var-children: \\e4e1;\n$fa-var-chalkboard: \\f51b;\n$fa-var-blackboard: \\f51b;\n$fa-var-user-large-slash: \\f4fa;\n$fa-var-user-alt-slash: \\f4fa;\n$fa-var-envelope-open: \\f2b6;\n$fa-var-handshake-simple-slash: \\e05f;\n$fa-var-handshake-alt-slash: \\e05f;\n$fa-var-mattress-pillow: \\e525;\n$fa-var-guarani-sign: \\e19a;\n$fa-var-arrows-rotate: \\f021;\n$fa-var-refresh: \\f021;\n$fa-var-sync: \\f021;\n$fa-var-fire-extinguisher: \\f134;\n$fa-var-cruzeiro-sign: \\e152;\n$fa-var-greater-than-equal: \\f532;\n$fa-var-shield-halved: \\f3ed;\n$fa-var-shield-alt: \\f3ed;\n$fa-var-book-atlas: \\f558;\n$fa-var-atlas: \\f558;\n$fa-var-virus: \\e074;\n$fa-var-envelope-circle-check: \\e4e8;\n$fa-var-layer-group: \\f5fd;\n$fa-var-arrows-to-dot: \\e4be;\n$fa-var-archway: \\f557;\n$fa-var-heart-circle-check: \\e4fd;\n$fa-var-house-chimney-crack: \\f6f1;\n$fa-var-house-damage: \\f6f1;\n$fa-var-file-zipper: \\f1c6;\n$fa-var-file-archive: \\f1c6;\n$fa-var-square: \\f0c8;\n$fa-var-martini-glass-empty: \\f000;\n$fa-var-glass-martini: \\f000;\n$fa-var-couch: \\f4b8;\n$fa-var-cedi-sign: \\e0df;\n$fa-var-italic: \\f033;\n$fa-var-table-cells-column-lock: \\e678;\n$fa-var-church: \\f51d;\n$fa-var-comments-dollar: \\f653;\n$fa-var-democrat: \\f747;\n$fa-var-z: \\5a;\n$fa-var-person-skiing: \\f7c9;\n$fa-var-skiing: \\f7c9;\n$fa-var-road-lock: \\e567;\n$fa-var-a: \\41;\n$fa-var-temperature-arrow-down: \\e03f;\n$fa-var-temperature-down: \\e03f;\n$fa-var-feather-pointed: \\f56b;\n$fa-var-feather-alt: \\f56b;\n$fa-var-p: \\50;\n$fa-var-snowflake: \\f2dc;\n$fa-var-newspaper: \\f1ea;\n$fa-var-rectangle-ad: \\f641;\n$fa-var-ad: \\f641;\n$fa-var-circle-arrow-right: \\f0a9;\n$fa-var-arrow-circle-right: \\f0a9;\n$fa-var-filter-circle-xmark: \\e17b;\n$fa-var-locust: \\e520;\n$fa-var-sort: \\f0dc;\n$fa-var-unsorted: \\f0dc;\n$fa-var-list-ol: \\f0cb;\n$fa-var-list-1-2: \\f0cb;\n$fa-var-list-numeric: \\f0cb;\n$fa-var-person-dress-burst: \\e544;\n$fa-var-money-check-dollar: \\f53d;\n$fa-var-money-check-alt: \\f53d;\n$fa-var-vector-square: \\f5cb;\n$fa-var-bread-slice: \\f7ec;\n$fa-var-language: \\f1ab;\n$fa-var-face-kiss-wink-heart: \\f598;\n$fa-var-kiss-wink-heart: \\f598;\n$fa-var-filter: \\f0b0;\n$fa-var-question: \\3f;\n$fa-var-file-signature: \\f573;\n$fa-var-up-down-left-right: \\f0b2;\n$fa-var-arrows-alt: \\f0b2;\n$fa-var-house-chimney-user: \\e065;\n$fa-var-hand-holding-heart: \\f4be;\n$fa-var-puzzle-piece: \\f12e;\n$fa-var-money-check: \\f53c;\n$fa-var-star-half-stroke: \\f5c0;\n$fa-var-star-half-alt: \\f5c0;\n$fa-var-code: \\f121;\n$fa-var-whiskey-glass: \\f7a0;\n$fa-var-glass-whiskey: \\f7a0;\n$fa-var-building-circle-exclamation: \\e4d3;\n$fa-var-magnifying-glass-chart: \\e522;\n$fa-var-arrow-up-right-from-square: \\f08e;\n$fa-var-external-link: \\f08e;\n$fa-var-cubes-stacked: \\e4e6;\n$fa-var-won-sign: \\f159;\n$fa-var-krw: \\f159;\n$fa-var-won: \\f159;\n$fa-var-virus-covid: \\e4a8;\n$fa-var-austral-sign: \\e0a9;\n$fa-var-f: \\46;\n$fa-var-leaf: \\f06c;\n$fa-var-road: \\f018;\n$fa-var-taxi: \\f1ba;\n$fa-var-cab: \\f1ba;\n$fa-var-person-circle-plus: \\e541;\n$fa-var-chart-pie: \\f200;\n$fa-var-pie-chart: \\f200;\n$fa-var-bolt-lightning: \\e0b7;\n$fa-var-sack-xmark: \\e56a;\n$fa-var-file-excel: \\f1c3;\n$fa-var-file-contract: \\f56c;\n$fa-var-fish-fins: \\e4f2;\n$fa-var-building-flag: \\e4d5;\n$fa-var-face-grin-beam: \\f582;\n$fa-var-grin-beam: \\f582;\n$fa-var-object-ungroup: \\f248;\n$fa-var-poop: \\f619;\n$fa-var-location-pin: \\f041;\n$fa-var-map-marker: \\f041;\n$fa-var-kaaba: \\f66b;\n$fa-var-toilet-paper: \\f71e;\n$fa-var-helmet-safety: \\f807;\n$fa-var-hard-hat: \\f807;\n$fa-var-hat-hard: \\f807;\n$fa-var-eject: \\f052;\n$fa-var-circle-right: \\f35a;\n$fa-var-arrow-alt-circle-right: \\f35a;\n$fa-var-plane-circle-check: \\e555;\n$fa-var-face-rolling-eyes: \\f5a5;\n$fa-var-meh-rolling-eyes: \\f5a5;\n$fa-var-object-group: \\f247;\n$fa-var-chart-line: \\f201;\n$fa-var-line-chart: \\f201;\n$fa-var-mask-ventilator: \\e524;\n$fa-var-arrow-right: \\f061;\n$fa-var-signs-post: \\f277;\n$fa-var-map-signs: \\f277;\n$fa-var-cash-register: \\f788;\n$fa-var-person-circle-question: \\e542;\n$fa-var-h: \\48;\n$fa-var-tarp: \\e57b;\n$fa-var-screwdriver-wrench: \\f7d9;\n$fa-var-tools: \\f7d9;\n$fa-var-arrows-to-eye: \\e4bf;\n$fa-var-plug-circle-bolt: \\e55b;\n$fa-var-heart: \\f004;\n$fa-var-mars-and-venus: \\f224;\n$fa-var-house-user: \\e1b0;\n$fa-var-home-user: \\e1b0;\n$fa-var-dumpster-fire: \\f794;\n$fa-var-house-crack: \\e3b1;\n$fa-var-martini-glass-citrus: \\f561;\n$fa-var-cocktail: \\f561;\n$fa-var-face-surprise: \\f5c2;\n$fa-var-surprise: \\f5c2;\n$fa-var-bottle-water: \\e4c5;\n$fa-var-circle-pause: \\f28b;\n$fa-var-pause-circle: \\f28b;\n$fa-var-toilet-paper-slash: \\e072;\n$fa-var-apple-whole: \\f5d1;\n$fa-var-apple-alt: \\f5d1;\n$fa-var-kitchen-set: \\e51a;\n$fa-var-r: \\52;\n$fa-var-temperature-quarter: \\f2ca;\n$fa-var-temperature-1: \\f2ca;\n$fa-var-thermometer-1: \\f2ca;\n$fa-var-thermometer-quarter: \\f2ca;\n$fa-var-cube: \\f1b2;\n$fa-var-bitcoin-sign: \\e0b4;\n$fa-var-shield-dog: \\e573;\n$fa-var-solar-panel: \\f5ba;\n$fa-var-lock-open: \\f3c1;\n$fa-var-elevator: \\e16d;\n$fa-var-money-bill-transfer: \\e528;\n$fa-var-money-bill-trend-up: \\e529;\n$fa-var-house-flood-water-circle-arrow-right: \\e50f;\n$fa-var-square-poll-horizontal: \\f682;\n$fa-var-poll-h: \\f682;\n$fa-var-circle: \\f111;\n$fa-var-backward-fast: \\f049;\n$fa-var-fast-backward: \\f049;\n$fa-var-recycle: \\f1b8;\n$fa-var-user-astronaut: \\f4fb;\n$fa-var-plane-slash: \\e069;\n$fa-var-trademark: \\f25c;\n$fa-var-basketball: \\f434;\n$fa-var-basketball-ball: \\f434;\n$fa-var-satellite-dish: \\f7c0;\n$fa-var-circle-up: \\f35b;\n$fa-var-arrow-alt-circle-up: \\f35b;\n$fa-var-mobile-screen-button: \\f3cd;\n$fa-var-mobile-alt: \\f3cd;\n$fa-var-volume-high: \\f028;\n$fa-var-volume-up: \\f028;\n$fa-var-users-rays: \\e593;\n$fa-var-wallet: \\f555;\n$fa-var-clipboard-check: \\f46c;\n$fa-var-file-audio: \\f1c7;\n$fa-var-burger: \\f805;\n$fa-var-hamburger: \\f805;\n$fa-var-wrench: \\f0ad;\n$fa-var-bugs: \\e4d0;\n$fa-var-rupee-sign: \\f156;\n$fa-var-rupee: \\f156;\n$fa-var-file-image: \\f1c5;\n$fa-var-circle-question: \\f059;\n$fa-var-question-circle: \\f059;\n$fa-var-plane-departure: \\f5b0;\n$fa-var-handshake-slash: \\e060;\n$fa-var-book-bookmark: \\e0bb;\n$fa-var-code-branch: \\f126;\n$fa-var-hat-cowboy: \\f8c0;\n$fa-var-bridge: \\e4c8;\n$fa-var-phone-flip: \\f879;\n$fa-var-phone-alt: \\f879;\n$fa-var-truck-front: \\e2b7;\n$fa-var-cat: \\f6be;\n$fa-var-anchor-circle-exclamation: \\e4ab;\n$fa-var-truck-field: \\e58d;\n$fa-var-route: \\f4d7;\n$fa-var-clipboard-question: \\e4e3;\n$fa-var-panorama: \\e209;\n$fa-var-comment-medical: \\f7f5;\n$fa-var-teeth-open: \\f62f;\n$fa-var-file-circle-minus: \\e4ed;\n$fa-var-tags: \\f02c;\n$fa-var-wine-glass: \\f4e3;\n$fa-var-forward-fast: \\f050;\n$fa-var-fast-forward: \\f050;\n$fa-var-face-meh-blank: \\f5a4;\n$fa-var-meh-blank: \\f5a4;\n$fa-var-square-parking: \\f540;\n$fa-var-parking: \\f540;\n$fa-var-house-signal: \\e012;\n$fa-var-bars-progress: \\f828;\n$fa-var-tasks-alt: \\f828;\n$fa-var-faucet-drip: \\e006;\n$fa-var-cart-flatbed: \\f474;\n$fa-var-dolly-flatbed: \\f474;\n$fa-var-ban-smoking: \\f54d;\n$fa-var-smoking-ban: \\f54d;\n$fa-var-terminal: \\f120;\n$fa-var-mobile-button: \\f10b;\n$fa-var-house-medical-flag: \\e514;\n$fa-var-basket-shopping: \\f291;\n$fa-var-shopping-basket: \\f291;\n$fa-var-tape: \\f4db;\n$fa-var-bus-simple: \\f55e;\n$fa-var-bus-alt: \\f55e;\n$fa-var-eye: \\f06e;\n$fa-var-face-sad-cry: \\f5b3;\n$fa-var-sad-cry: \\f5b3;\n$fa-var-audio-description: \\f29e;\n$fa-var-person-military-to-person: \\e54c;\n$fa-var-file-shield: \\e4f0;\n$fa-var-user-slash: \\f506;\n$fa-var-pen: \\f304;\n$fa-var-tower-observation: \\e586;\n$fa-var-file-code: \\f1c9;\n$fa-var-signal: \\f012;\n$fa-var-signal-5: \\f012;\n$fa-var-signal-perfect: \\f012;\n$fa-var-bus: \\f207;\n$fa-var-heart-circle-xmark: \\e501;\n$fa-var-house-chimney: \\e3af;\n$fa-var-home-lg: \\e3af;\n$fa-var-window-maximize: \\f2d0;\n$fa-var-face-frown: \\f119;\n$fa-var-frown: \\f119;\n$fa-var-prescription: \\f5b1;\n$fa-var-shop: \\f54f;\n$fa-var-store-alt: \\f54f;\n$fa-var-floppy-disk: \\f0c7;\n$fa-var-save: \\f0c7;\n$fa-var-vihara: \\f6a7;\n$fa-var-scale-unbalanced: \\f515;\n$fa-var-balance-scale-left: \\f515;\n$fa-var-sort-up: \\f0de;\n$fa-var-sort-asc: \\f0de;\n$fa-var-comment-dots: \\f4ad;\n$fa-var-commenting: \\f4ad;\n$fa-var-plant-wilt: \\e5aa;\n$fa-var-diamond: \\f219;\n$fa-var-face-grin-squint: \\f585;\n$fa-var-grin-squint: \\f585;\n$fa-var-hand-holding-dollar: \\f4c0;\n$fa-var-hand-holding-usd: \\f4c0;\n$fa-var-chart-diagram: \\e695;\n$fa-var-bacterium: \\e05a;\n$fa-var-hand-pointer: \\f25a;\n$fa-var-drum-steelpan: \\f56a;\n$fa-var-hand-scissors: \\f257;\n$fa-var-hands-praying: \\f684;\n$fa-var-praying-hands: \\f684;\n$fa-var-arrow-rotate-right: \\f01e;\n$fa-var-arrow-right-rotate: \\f01e;\n$fa-var-arrow-rotate-forward: \\f01e;\n$fa-var-redo: \\f01e;\n$fa-var-biohazard: \\f780;\n$fa-var-location-crosshairs: \\f601;\n$fa-var-location: \\f601;\n$fa-var-mars-double: \\f227;\n$fa-var-child-dress: \\e59c;\n$fa-var-users-between-lines: \\e591;\n$fa-var-lungs-virus: \\e067;\n$fa-var-face-grin-tears: \\f588;\n$fa-var-grin-tears: \\f588;\n$fa-var-phone: \\f095;\n$fa-var-calendar-xmark: \\f273;\n$fa-var-calendar-times: \\f273;\n$fa-var-child-reaching: \\e59d;\n$fa-var-head-side-virus: \\e064;\n$fa-var-user-gear: \\f4fe;\n$fa-var-user-cog: \\f4fe;\n$fa-var-arrow-up-1-9: \\f163;\n$fa-var-sort-numeric-up: \\f163;\n$fa-var-door-closed: \\f52a;\n$fa-var-shield-virus: \\e06c;\n$fa-var-dice-six: \\f526;\n$fa-var-mosquito-net: \\e52c;\n$fa-var-file-fragment: \\e697;\n$fa-var-bridge-water: \\e4ce;\n$fa-var-person-booth: \\f756;\n$fa-var-text-width: \\f035;\n$fa-var-hat-wizard: \\f6e8;\n$fa-var-pen-fancy: \\f5ac;\n$fa-var-person-digging: \\f85e;\n$fa-var-digging: \\f85e;\n$fa-var-trash: \\f1f8;\n$fa-var-gauge-simple: \\f629;\n$fa-var-gauge-simple-med: \\f629;\n$fa-var-tachometer-average: \\f629;\n$fa-var-book-medical: \\f7e6;\n$fa-var-poo: \\f2fe;\n$fa-var-quote-right: \\f10e;\n$fa-var-quote-right-alt: \\f10e;\n$fa-var-shirt: \\f553;\n$fa-var-t-shirt: \\f553;\n$fa-var-tshirt: \\f553;\n$fa-var-cubes: \\f1b3;\n$fa-var-divide: \\f529;\n$fa-var-tenge-sign: \\f7d7;\n$fa-var-tenge: \\f7d7;\n$fa-var-headphones: \\f025;\n$fa-var-hands-holding: \\f4c2;\n$fa-var-hands-clapping: \\e1a8;\n$fa-var-republican: \\f75e;\n$fa-var-arrow-left: \\f060;\n$fa-var-person-circle-xmark: \\e543;\n$fa-var-ruler: \\f545;\n$fa-var-align-left: \\f036;\n$fa-var-dice-d6: \\f6d1;\n$fa-var-restroom: \\f7bd;\n$fa-var-j: \\4a;\n$fa-var-users-viewfinder: \\e595;\n$fa-var-file-video: \\f1c8;\n$fa-var-up-right-from-square: \\f35d;\n$fa-var-external-link-alt: \\f35d;\n$fa-var-table-cells: \\f00a;\n$fa-var-th: \\f00a;\n$fa-var-file-pdf: \\f1c1;\n$fa-var-book-bible: \\f647;\n$fa-var-bible: \\f647;\n$fa-var-o: \\4f;\n$fa-var-suitcase-medical: \\f0fa;\n$fa-var-medkit: \\f0fa;\n$fa-var-user-secret: \\f21b;\n$fa-var-otter: \\f700;\n$fa-var-person-dress: \\f182;\n$fa-var-female: \\f182;\n$fa-var-comment-dollar: \\f651;\n$fa-var-business-time: \\f64a;\n$fa-var-briefcase-clock: \\f64a;\n$fa-var-table-cells-large: \\f009;\n$fa-var-th-large: \\f009;\n$fa-var-book-tanakh: \\f827;\n$fa-var-tanakh: \\f827;\n$fa-var-phone-volume: \\f2a0;\n$fa-var-volume-control-phone: \\f2a0;\n$fa-var-hat-cowboy-side: \\f8c1;\n$fa-var-clipboard-user: \\f7f3;\n$fa-var-child: \\f1ae;\n$fa-var-lira-sign: \\f195;\n$fa-var-satellite: \\f7bf;\n$fa-var-plane-lock: \\e558;\n$fa-var-tag: \\f02b;\n$fa-var-comment: \\f075;\n$fa-var-cake-candles: \\f1fd;\n$fa-var-birthday-cake: \\f1fd;\n$fa-var-cake: \\f1fd;\n$fa-var-envelope: \\f0e0;\n$fa-var-angles-up: \\f102;\n$fa-var-angle-double-up: \\f102;\n$fa-var-paperclip: \\f0c6;\n$fa-var-arrow-right-to-city: \\e4b3;\n$fa-var-ribbon: \\f4d6;\n$fa-var-lungs: \\f604;\n$fa-var-arrow-up-9-1: \\f887;\n$fa-var-sort-numeric-up-alt: \\f887;\n$fa-var-litecoin-sign: \\e1d3;\n$fa-var-border-none: \\f850;\n$fa-var-circle-nodes: \\e4e2;\n$fa-var-parachute-box: \\f4cd;\n$fa-var-indent: \\f03c;\n$fa-var-truck-field-un: \\e58e;\n$fa-var-hourglass: \\f254;\n$fa-var-hourglass-empty: \\f254;\n$fa-var-mountain: \\f6fc;\n$fa-var-user-doctor: \\f0f0;\n$fa-var-user-md: \\f0f0;\n$fa-var-circle-info: \\f05a;\n$fa-var-info-circle: \\f05a;\n$fa-var-cloud-meatball: \\f73b;\n$fa-var-camera: \\f030;\n$fa-var-camera-alt: \\f030;\n$fa-var-square-virus: \\e578;\n$fa-var-meteor: \\f753;\n$fa-var-car-on: \\e4dd;\n$fa-var-sleigh: \\f7cc;\n$fa-var-arrow-down-1-9: \\f162;\n$fa-var-sort-numeric-asc: \\f162;\n$fa-var-sort-numeric-down: \\f162;\n$fa-var-hand-holding-droplet: \\f4c1;\n$fa-var-hand-holding-water: \\f4c1;\n$fa-var-water: \\f773;\n$fa-var-calendar-check: \\f274;\n$fa-var-braille: \\f2a1;\n$fa-var-prescription-bottle-medical: \\f486;\n$fa-var-prescription-bottle-alt: \\f486;\n$fa-var-landmark: \\f66f;\n$fa-var-truck: \\f0d1;\n$fa-var-crosshairs: \\f05b;\n$fa-var-person-cane: \\e53c;\n$fa-var-tent: \\e57d;\n$fa-var-vest-patches: \\e086;\n$fa-var-check-double: \\f560;\n$fa-var-arrow-down-a-z: \\f15d;\n$fa-var-sort-alpha-asc: \\f15d;\n$fa-var-sort-alpha-down: \\f15d;\n$fa-var-money-bill-wheat: \\e52a;\n$fa-var-cookie: \\f563;\n$fa-var-arrow-rotate-left: \\f0e2;\n$fa-var-arrow-left-rotate: \\f0e2;\n$fa-var-arrow-rotate-back: \\f0e2;\n$fa-var-arrow-rotate-backward: \\f0e2;\n$fa-var-undo: \\f0e2;\n$fa-var-hard-drive: \\f0a0;\n$fa-var-hdd: \\f0a0;\n$fa-var-face-grin-squint-tears: \\f586;\n$fa-var-grin-squint-tears: \\f586;\n$fa-var-dumbbell: \\f44b;\n$fa-var-rectangle-list: \\f022;\n$fa-var-list-alt: \\f022;\n$fa-var-tarp-droplet: \\e57c;\n$fa-var-house-medical-circle-check: \\e511;\n$fa-var-person-skiing-nordic: \\f7ca;\n$fa-var-skiing-nordic: \\f7ca;\n$fa-var-calendar-plus: \\f271;\n$fa-var-plane-arrival: \\f5af;\n$fa-var-circle-left: \\f359;\n$fa-var-arrow-alt-circle-left: \\f359;\n$fa-var-train-subway: \\f239;\n$fa-var-subway: \\f239;\n$fa-var-chart-gantt: \\e0e4;\n$fa-var-indian-rupee-sign: \\e1bc;\n$fa-var-indian-rupee: \\e1bc;\n$fa-var-inr: \\e1bc;\n$fa-var-crop-simple: \\f565;\n$fa-var-crop-alt: \\f565;\n$fa-var-money-bill-1: \\f3d1;\n$fa-var-money-bill-alt: \\f3d1;\n$fa-var-left-long: \\f30a;\n$fa-var-long-arrow-alt-left: \\f30a;\n$fa-var-dna: \\f471;\n$fa-var-virus-slash: \\e075;\n$fa-var-minus: \\f068;\n$fa-var-subtract: \\f068;\n$fa-var-chess: \\f439;\n$fa-var-arrow-left-long: \\f177;\n$fa-var-long-arrow-left: \\f177;\n$fa-var-plug-circle-check: \\e55c;\n$fa-var-street-view: \\f21d;\n$fa-var-franc-sign: \\e18f;\n$fa-var-volume-off: \\f026;\n$fa-var-hands-asl-interpreting: \\f2a3;\n$fa-var-american-sign-language-interpreting: \\f2a3;\n$fa-var-asl-interpreting: \\f2a3;\n$fa-var-hands-american-sign-language-interpreting: \\f2a3;\n$fa-var-gear: \\f013;\n$fa-var-cog: \\f013;\n$fa-var-droplet-slash: \\f5c7;\n$fa-var-tint-slash: \\f5c7;\n$fa-var-mosque: \\f678;\n$fa-var-mosquito: \\e52b;\n$fa-var-star-of-david: \\f69a;\n$fa-var-person-military-rifle: \\e54b;\n$fa-var-cart-shopping: \\f07a;\n$fa-var-shopping-cart: \\f07a;\n$fa-var-vials: \\f493;\n$fa-var-plug-circle-plus: \\e55f;\n$fa-var-place-of-worship: \\f67f;\n$fa-var-grip-vertical: \\f58e;\n$fa-var-hexagon-nodes: \\e699;\n$fa-var-arrow-turn-up: \\f148;\n$fa-var-level-up: \\f148;\n$fa-var-u: \\55;\n$fa-var-square-root-variable: \\f698;\n$fa-var-square-root-alt: \\f698;\n$fa-var-clock: \\f017;\n$fa-var-clock-four: \\f017;\n$fa-var-backward-step: \\f048;\n$fa-var-step-backward: \\f048;\n$fa-var-pallet: \\f482;\n$fa-var-faucet: \\e005;\n$fa-var-baseball-bat-ball: \\f432;\n$fa-var-s: \\53;\n$fa-var-timeline: \\e29c;\n$fa-var-keyboard: \\f11c;\n$fa-var-caret-down: \\f0d7;\n$fa-var-house-chimney-medical: \\f7f2;\n$fa-var-clinic-medical: \\f7f2;\n$fa-var-temperature-three-quarters: \\f2c8;\n$fa-var-temperature-3: \\f2c8;\n$fa-var-thermometer-3: \\f2c8;\n$fa-var-thermometer-three-quarters: \\f2c8;\n$fa-var-mobile-screen: \\f3cf;\n$fa-var-mobile-android-alt: \\f3cf;\n$fa-var-plane-up: \\e22d;\n$fa-var-piggy-bank: \\f4d3;\n$fa-var-battery-half: \\f242;\n$fa-var-battery-3: \\f242;\n$fa-var-mountain-city: \\e52e;\n$fa-var-coins: \\f51e;\n$fa-var-khanda: \\f66d;\n$fa-var-sliders: \\f1de;\n$fa-var-sliders-h: \\f1de;\n$fa-var-folder-tree: \\f802;\n$fa-var-network-wired: \\f6ff;\n$fa-var-map-pin: \\f276;\n$fa-var-hamsa: \\f665;\n$fa-var-cent-sign: \\e3f5;\n$fa-var-flask: \\f0c3;\n$fa-var-person-pregnant: \\e31e;\n$fa-var-wand-sparkles: \\f72b;\n$fa-var-ellipsis-vertical: \\f142;\n$fa-var-ellipsis-v: \\f142;\n$fa-var-ticket: \\f145;\n$fa-var-power-off: \\f011;\n$fa-var-right-long: \\f30b;\n$fa-var-long-arrow-alt-right: \\f30b;\n$fa-var-flag-usa: \\f74d;\n$fa-var-laptop-file: \\e51d;\n$fa-var-tty: \\f1e4;\n$fa-var-teletype: \\f1e4;\n$fa-var-diagram-next: \\e476;\n$fa-var-person-rifle: \\e54e;\n$fa-var-house-medical-circle-exclamation: \\e512;\n$fa-var-closed-captioning: \\f20a;\n$fa-var-person-hiking: \\f6ec;\n$fa-var-hiking: \\f6ec;\n$fa-var-venus-double: \\f226;\n$fa-var-images: \\f302;\n$fa-var-calculator: \\f1ec;\n$fa-var-people-pulling: \\e535;\n$fa-var-n: \\4e;\n$fa-var-cable-car: \\f7da;\n$fa-var-tram: \\f7da;\n$fa-var-cloud-rain: \\f73d;\n$fa-var-building-circle-xmark: \\e4d4;\n$fa-var-ship: \\f21a;\n$fa-var-arrows-down-to-line: \\e4b8;\n$fa-var-download: \\f019;\n$fa-var-face-grin: \\f580;\n$fa-var-grin: \\f580;\n$fa-var-delete-left: \\f55a;\n$fa-var-backspace: \\f55a;\n$fa-var-eye-dropper: \\f1fb;\n$fa-var-eye-dropper-empty: \\f1fb;\n$fa-var-eyedropper: \\f1fb;\n$fa-var-file-circle-check: \\e5a0;\n$fa-var-forward: \\f04e;\n$fa-var-mobile: \\f3ce;\n$fa-var-mobile-android: \\f3ce;\n$fa-var-mobile-phone: \\f3ce;\n$fa-var-face-meh: \\f11a;\n$fa-var-meh: \\f11a;\n$fa-var-align-center: \\f037;\n$fa-var-book-skull: \\f6b7;\n$fa-var-book-dead: \\f6b7;\n$fa-var-id-card: \\f2c2;\n$fa-var-drivers-license: \\f2c2;\n$fa-var-outdent: \\f03b;\n$fa-var-dedent: \\f03b;\n$fa-var-heart-circle-exclamation: \\e4fe;\n$fa-var-house: \\f015;\n$fa-var-home: \\f015;\n$fa-var-home-alt: \\f015;\n$fa-var-home-lg-alt: \\f015;\n$fa-var-calendar-week: \\f784;\n$fa-var-laptop-medical: \\f812;\n$fa-var-b: \\42;\n$fa-var-file-medical: \\f477;\n$fa-var-dice-one: \\f525;\n$fa-var-kiwi-bird: \\f535;\n$fa-var-arrow-right-arrow-left: \\f0ec;\n$fa-var-exchange: \\f0ec;\n$fa-var-rotate-right: \\f2f9;\n$fa-var-redo-alt: \\f2f9;\n$fa-var-rotate-forward: \\f2f9;\n$fa-var-utensils: \\f2e7;\n$fa-var-cutlery: \\f2e7;\n$fa-var-arrow-up-wide-short: \\f161;\n$fa-var-sort-amount-up: \\f161;\n$fa-var-mill-sign: \\e1ed;\n$fa-var-bowl-rice: \\e2eb;\n$fa-var-skull: \\f54c;\n$fa-var-tower-broadcast: \\f519;\n$fa-var-broadcast-tower: \\f519;\n$fa-var-truck-pickup: \\f63c;\n$fa-var-up-long: \\f30c;\n$fa-var-long-arrow-alt-up: \\f30c;\n$fa-var-stop: \\f04d;\n$fa-var-code-merge: \\f387;\n$fa-var-upload: \\f093;\n$fa-var-hurricane: \\f751;\n$fa-var-mound: \\e52d;\n$fa-var-toilet-portable: \\e583;\n$fa-var-compact-disc: \\f51f;\n$fa-var-file-arrow-down: \\f56d;\n$fa-var-file-download: \\f56d;\n$fa-var-caravan: \\f8ff;\n$fa-var-shield-cat: \\e572;\n$fa-var-bolt: \\f0e7;\n$fa-var-zap: \\f0e7;\n$fa-var-glass-water: \\e4f4;\n$fa-var-oil-well: \\e532;\n$fa-var-vault: \\e2c5;\n$fa-var-mars: \\f222;\n$fa-var-toilet: \\f7d8;\n$fa-var-plane-circle-xmark: \\e557;\n$fa-var-yen-sign: \\f157;\n$fa-var-cny: \\f157;\n$fa-var-jpy: \\f157;\n$fa-var-rmb: \\f157;\n$fa-var-yen: \\f157;\n$fa-var-ruble-sign: \\f158;\n$fa-var-rouble: \\f158;\n$fa-var-rub: \\f158;\n$fa-var-ruble: \\f158;\n$fa-var-sun: \\f185;\n$fa-var-guitar: \\f7a6;\n$fa-var-face-laugh-wink: \\f59c;\n$fa-var-laugh-wink: \\f59c;\n$fa-var-horse-head: \\f7ab;\n$fa-var-bore-hole: \\e4c3;\n$fa-var-industry: \\f275;\n$fa-var-circle-down: \\f358;\n$fa-var-arrow-alt-circle-down: \\f358;\n$fa-var-arrows-turn-to-dots: \\e4c1;\n$fa-var-florin-sign: \\e184;\n$fa-var-arrow-down-short-wide: \\f884;\n$fa-var-sort-amount-desc: \\f884;\n$fa-var-sort-amount-down-alt: \\f884;\n$fa-var-less-than: \\3c;\n$fa-var-angle-down: \\f107;\n$fa-var-car-tunnel: \\e4de;\n$fa-var-head-side-cough: \\e061;\n$fa-var-grip-lines: \\f7a4;\n$fa-var-thumbs-down: \\f165;\n$fa-var-user-lock: \\f502;\n$fa-var-arrow-right-long: \\f178;\n$fa-var-long-arrow-right: \\f178;\n$fa-var-anchor-circle-xmark: \\e4ac;\n$fa-var-ellipsis: \\f141;\n$fa-var-ellipsis-h: \\f141;\n$fa-var-chess-pawn: \\f443;\n$fa-var-kit-medical: \\f479;\n$fa-var-first-aid: \\f479;\n$fa-var-person-through-window: \\e5a9;\n$fa-var-toolbox: \\f552;\n$fa-var-hands-holding-circle: \\e4fb;\n$fa-var-bug: \\f188;\n$fa-var-credit-card: \\f09d;\n$fa-var-credit-card-alt: \\f09d;\n$fa-var-car: \\f1b9;\n$fa-var-automobile: \\f1b9;\n$fa-var-hand-holding-hand: \\e4f7;\n$fa-var-book-open-reader: \\f5da;\n$fa-var-book-reader: \\f5da;\n$fa-var-mountain-sun: \\e52f;\n$fa-var-arrows-left-right-to-line: \\e4ba;\n$fa-var-dice-d20: \\f6cf;\n$fa-var-truck-droplet: \\e58c;\n$fa-var-file-circle-xmark: \\e5a1;\n$fa-var-temperature-arrow-up: \\e040;\n$fa-var-temperature-up: \\e040;\n$fa-var-medal: \\f5a2;\n$fa-var-bed: \\f236;\n$fa-var-square-h: \\f0fd;\n$fa-var-h-square: \\f0fd;\n$fa-var-podcast: \\f2ce;\n$fa-var-temperature-full: \\f2c7;\n$fa-var-temperature-4: \\f2c7;\n$fa-var-thermometer-4: \\f2c7;\n$fa-var-thermometer-full: \\f2c7;\n$fa-var-bell: \\f0f3;\n$fa-var-superscript: \\f12b;\n$fa-var-plug-circle-xmark: \\e560;\n$fa-var-star-of-life: \\f621;\n$fa-var-phone-slash: \\f3dd;\n$fa-var-paint-roller: \\f5aa;\n$fa-var-handshake-angle: \\f4c4;\n$fa-var-hands-helping: \\f4c4;\n$fa-var-location-dot: \\f3c5;\n$fa-var-map-marker-alt: \\f3c5;\n$fa-var-file: \\f15b;\n$fa-var-greater-than: \\3e;\n$fa-var-person-swimming: \\f5c4;\n$fa-var-swimmer: \\f5c4;\n$fa-var-arrow-down: \\f063;\n$fa-var-droplet: \\f043;\n$fa-var-tint: \\f043;\n$fa-var-eraser: \\f12d;\n$fa-var-earth-americas: \\f57d;\n$fa-var-earth: \\f57d;\n$fa-var-earth-america: \\f57d;\n$fa-var-globe-americas: \\f57d;\n$fa-var-person-burst: \\e53b;\n$fa-var-dove: \\f4ba;\n$fa-var-battery-empty: \\f244;\n$fa-var-battery-0: \\f244;\n$fa-var-socks: \\f696;\n$fa-var-inbox: \\f01c;\n$fa-var-section: \\e447;\n$fa-var-gauge-high: \\f625;\n$fa-var-tachometer-alt: \\f625;\n$fa-var-tachometer-alt-fast: \\f625;\n$fa-var-envelope-open-text: \\f658;\n$fa-var-hospital: \\f0f8;\n$fa-var-hospital-alt: \\f0f8;\n$fa-var-hospital-wide: \\f0f8;\n$fa-var-wine-bottle: \\f72f;\n$fa-var-chess-rook: \\f447;\n$fa-var-bars-staggered: \\f550;\n$fa-var-reorder: \\f550;\n$fa-var-stream: \\f550;\n$fa-var-dharmachakra: \\f655;\n$fa-var-hotdog: \\f80f;\n$fa-var-person-walking-with-cane: \\f29d;\n$fa-var-blind: \\f29d;\n$fa-var-drum: \\f569;\n$fa-var-ice-cream: \\f810;\n$fa-var-heart-circle-bolt: \\e4fc;\n$fa-var-fax: \\f1ac;\n$fa-var-paragraph: \\f1dd;\n$fa-var-check-to-slot: \\f772;\n$fa-var-vote-yea: \\f772;\n$fa-var-star-half: \\f089;\n$fa-var-boxes-stacked: \\f468;\n$fa-var-boxes: \\f468;\n$fa-var-boxes-alt: \\f468;\n$fa-var-link: \\f0c1;\n$fa-var-chain: \\f0c1;\n$fa-var-ear-listen: \\f2a2;\n$fa-var-assistive-listening-systems: \\f2a2;\n$fa-var-tree-city: \\e587;\n$fa-var-play: \\f04b;\n$fa-var-font: \\f031;\n$fa-var-table-cells-row-lock: \\e67a;\n$fa-var-rupiah-sign: \\e23d;\n$fa-var-magnifying-glass: \\f002;\n$fa-var-search: \\f002;\n$fa-var-table-tennis-paddle-ball: \\f45d;\n$fa-var-ping-pong-paddle-ball: \\f45d;\n$fa-var-table-tennis: \\f45d;\n$fa-var-person-dots-from-line: \\f470;\n$fa-var-diagnoses: \\f470;\n$fa-var-trash-can-arrow-up: \\f82a;\n$fa-var-trash-restore-alt: \\f82a;\n$fa-var-naira-sign: \\e1f6;\n$fa-var-cart-arrow-down: \\f218;\n$fa-var-walkie-talkie: \\f8ef;\n$fa-var-file-pen: \\f31c;\n$fa-var-file-edit: \\f31c;\n$fa-var-receipt: \\f543;\n$fa-var-square-pen: \\f14b;\n$fa-var-pen-square: \\f14b;\n$fa-var-pencil-square: \\f14b;\n$fa-var-suitcase-rolling: \\f5c1;\n$fa-var-person-circle-exclamation: \\e53f;\n$fa-var-chevron-down: \\f078;\n$fa-var-battery-full: \\f240;\n$fa-var-battery: \\f240;\n$fa-var-battery-5: \\f240;\n$fa-var-skull-crossbones: \\f714;\n$fa-var-code-compare: \\e13a;\n$fa-var-list-ul: \\f0ca;\n$fa-var-list-dots: \\f0ca;\n$fa-var-school-lock: \\e56f;\n$fa-var-tower-cell: \\e585;\n$fa-var-down-long: \\f309;\n$fa-var-long-arrow-alt-down: \\f309;\n$fa-var-ranking-star: \\e561;\n$fa-var-chess-king: \\f43f;\n$fa-var-person-harassing: \\e549;\n$fa-var-brazilian-real-sign: \\e46c;\n$fa-var-landmark-dome: \\f752;\n$fa-var-landmark-alt: \\f752;\n$fa-var-arrow-up: \\f062;\n$fa-var-tv: \\f26c;\n$fa-var-television: \\f26c;\n$fa-var-tv-alt: \\f26c;\n$fa-var-shrimp: \\e448;\n$fa-var-list-check: \\f0ae;\n$fa-var-tasks: \\f0ae;\n$fa-var-jug-detergent: \\e519;\n$fa-var-circle-user: \\f2bd;\n$fa-var-user-circle: \\f2bd;\n$fa-var-user-shield: \\f505;\n$fa-var-wind: \\f72e;\n$fa-var-car-burst: \\f5e1;\n$fa-var-car-crash: \\f5e1;\n$fa-var-y: \\59;\n$fa-var-person-snowboarding: \\f7ce;\n$fa-var-snowboarding: \\f7ce;\n$fa-var-truck-fast: \\f48b;\n$fa-var-shipping-fast: \\f48b;\n$fa-var-fish: \\f578;\n$fa-var-user-graduate: \\f501;\n$fa-var-circle-half-stroke: \\f042;\n$fa-var-adjust: \\f042;\n$fa-var-clapperboard: \\e131;\n$fa-var-circle-radiation: \\f7ba;\n$fa-var-radiation-alt: \\f7ba;\n$fa-var-baseball: \\f433;\n$fa-var-baseball-ball: \\f433;\n$fa-var-jet-fighter-up: \\e518;\n$fa-var-diagram-project: \\f542;\n$fa-var-project-diagram: \\f542;\n$fa-var-copy: \\f0c5;\n$fa-var-volume-xmark: \\f6a9;\n$fa-var-volume-mute: \\f6a9;\n$fa-var-volume-times: \\f6a9;\n$fa-var-hand-sparkles: \\e05d;\n$fa-var-grip: \\f58d;\n$fa-var-grip-horizontal: \\f58d;\n$fa-var-share-from-square: \\f14d;\n$fa-var-share-square: \\f14d;\n$fa-var-child-combatant: \\e4e0;\n$fa-var-child-rifle: \\e4e0;\n$fa-var-gun: \\e19b;\n$fa-var-square-phone: \\f098;\n$fa-var-phone-square: \\f098;\n$fa-var-plus: \\2b;\n$fa-var-add: \\2b;\n$fa-var-expand: \\f065;\n$fa-var-computer: \\e4e5;\n$fa-var-xmark: \\f00d;\n$fa-var-close: \\f00d;\n$fa-var-multiply: \\f00d;\n$fa-var-remove: \\f00d;\n$fa-var-times: \\f00d;\n$fa-var-arrows-up-down-left-right: \\f047;\n$fa-var-arrows: \\f047;\n$fa-var-chalkboard-user: \\f51c;\n$fa-var-chalkboard-teacher: \\f51c;\n$fa-var-peso-sign: \\e222;\n$fa-var-building-shield: \\e4d8;\n$fa-var-baby: \\f77c;\n$fa-var-users-line: \\e592;\n$fa-var-quote-left: \\f10d;\n$fa-var-quote-left-alt: \\f10d;\n$fa-var-tractor: \\f722;\n$fa-var-trash-arrow-up: \\f829;\n$fa-var-trash-restore: \\f829;\n$fa-var-arrow-down-up-lock: \\e4b0;\n$fa-var-lines-leaning: \\e51e;\n$fa-var-ruler-combined: \\f546;\n$fa-var-copyright: \\f1f9;\n$fa-var-equals: \\3d;\n$fa-var-blender: \\f517;\n$fa-var-teeth: \\f62e;\n$fa-var-shekel-sign: \\f20b;\n$fa-var-ils: \\f20b;\n$fa-var-shekel: \\f20b;\n$fa-var-sheqel: \\f20b;\n$fa-var-sheqel-sign: \\f20b;\n$fa-var-map: \\f279;\n$fa-var-rocket: \\f135;\n$fa-var-photo-film: \\f87c;\n$fa-var-photo-video: \\f87c;\n$fa-var-folder-minus: \\f65d;\n$fa-var-hexagon-nodes-bolt: \\e69a;\n$fa-var-store: \\f54e;\n$fa-var-arrow-trend-up: \\e098;\n$fa-var-plug-circle-minus: \\e55e;\n$fa-var-sign-hanging: \\f4d9;\n$fa-var-sign: \\f4d9;\n$fa-var-bezier-curve: \\f55b;\n$fa-var-bell-slash: \\f1f6;\n$fa-var-tablet: \\f3fb;\n$fa-var-tablet-android: \\f3fb;\n$fa-var-school-flag: \\e56e;\n$fa-var-fill: \\f575;\n$fa-var-angle-up: \\f106;\n$fa-var-drumstick-bite: \\f6d7;\n$fa-var-holly-berry: \\f7aa;\n$fa-var-chevron-left: \\f053;\n$fa-var-bacteria: \\e059;\n$fa-var-hand-lizard: \\f258;\n$fa-var-notdef: \\e1fe;\n$fa-var-disease: \\f7fa;\n$fa-var-briefcase-medical: \\f469;\n$fa-var-genderless: \\f22d;\n$fa-var-chevron-right: \\f054;\n$fa-var-retweet: \\f079;\n$fa-var-car-rear: \\f5de;\n$fa-var-car-alt: \\f5de;\n$fa-var-pump-soap: \\e06b;\n$fa-var-video-slash: \\f4e2;\n$fa-var-battery-quarter: \\f243;\n$fa-var-battery-2: \\f243;\n$fa-var-radio: \\f8d7;\n$fa-var-baby-carriage: \\f77d;\n$fa-var-carriage-baby: \\f77d;\n$fa-var-traffic-light: \\f637;\n$fa-var-thermometer: \\f491;\n$fa-var-vr-cardboard: \\f729;\n$fa-var-hand-middle-finger: \\f806;\n$fa-var-percent: \\25;\n$fa-var-percentage: \\25;\n$fa-var-truck-moving: \\f4df;\n$fa-var-glass-water-droplet: \\e4f5;\n$fa-var-display: \\e163;\n$fa-var-face-smile: \\f118;\n$fa-var-smile: \\f118;\n$fa-var-thumbtack: \\f08d;\n$fa-var-thumb-tack: \\f08d;\n$fa-var-trophy: \\f091;\n$fa-var-person-praying: \\f683;\n$fa-var-pray: \\f683;\n$fa-var-hammer: \\f6e3;\n$fa-var-hand-peace: \\f25b;\n$fa-var-rotate: \\f2f1;\n$fa-var-sync-alt: \\f2f1;\n$fa-var-spinner: \\f110;\n$fa-var-robot: \\f544;\n$fa-var-peace: \\f67c;\n$fa-var-gears: \\f085;\n$fa-var-cogs: \\f085;\n$fa-var-warehouse: \\f494;\n$fa-var-arrow-up-right-dots: \\e4b7;\n$fa-var-splotch: \\f5bc;\n$fa-var-face-grin-hearts: \\f584;\n$fa-var-grin-hearts: \\f584;\n$fa-var-dice-four: \\f524;\n$fa-var-sim-card: \\f7c4;\n$fa-var-transgender: \\f225;\n$fa-var-transgender-alt: \\f225;\n$fa-var-mercury: \\f223;\n$fa-var-arrow-turn-down: \\f149;\n$fa-var-level-down: \\f149;\n$fa-var-person-falling-burst: \\e547;\n$fa-var-award: \\f559;\n$fa-var-ticket-simple: \\f3ff;\n$fa-var-ticket-alt: \\f3ff;\n$fa-var-building: \\f1ad;\n$fa-var-angles-left: \\f100;\n$fa-var-angle-double-left: \\f100;\n$fa-var-qrcode: \\f029;\n$fa-var-clock-rotate-left: \\f1da;\n$fa-var-history: \\f1da;\n$fa-var-face-grin-beam-sweat: \\f583;\n$fa-var-grin-beam-sweat: \\f583;\n$fa-var-file-export: \\f56e;\n$fa-var-arrow-right-from-file: \\f56e;\n$fa-var-shield: \\f132;\n$fa-var-shield-blank: \\f132;\n$fa-var-arrow-up-short-wide: \\f885;\n$fa-var-sort-amount-up-alt: \\f885;\n$fa-var-comment-nodes: \\e696;\n$fa-var-house-medical: \\e3b2;\n$fa-var-golf-ball-tee: \\f450;\n$fa-var-golf-ball: \\f450;\n$fa-var-circle-chevron-left: \\f137;\n$fa-var-chevron-circle-left: \\f137;\n$fa-var-house-chimney-window: \\e00d;\n$fa-var-pen-nib: \\f5ad;\n$fa-var-tent-arrow-turn-left: \\e580;\n$fa-var-tents: \\e582;\n$fa-var-wand-magic: \\f0d0;\n$fa-var-magic: \\f0d0;\n$fa-var-dog: \\f6d3;\n$fa-var-carrot: \\f787;\n$fa-var-moon: \\f186;\n$fa-var-wine-glass-empty: \\f5ce;\n$fa-var-wine-glass-alt: \\f5ce;\n$fa-var-cheese: \\f7ef;\n$fa-var-yin-yang: \\f6ad;\n$fa-var-music: \\f001;\n$fa-var-code-commit: \\f386;\n$fa-var-temperature-low: \\f76b;\n$fa-var-person-biking: \\f84a;\n$fa-var-biking: \\f84a;\n$fa-var-broom: \\f51a;\n$fa-var-shield-heart: \\e574;\n$fa-var-gopuram: \\f664;\n$fa-var-earth-oceania: \\e47b;\n$fa-var-globe-oceania: \\e47b;\n$fa-var-square-xmark: \\f2d3;\n$fa-var-times-square: \\f2d3;\n$fa-var-xmark-square: \\f2d3;\n$fa-var-hashtag: \\23;\n$fa-var-up-right-and-down-left-from-center: \\f424;\n$fa-var-expand-alt: \\f424;\n$fa-var-oil-can: \\f613;\n$fa-var-t: \\54;\n$fa-var-hippo: \\f6ed;\n$fa-var-chart-column: \\e0e3;\n$fa-var-infinity: \\f534;\n$fa-var-vial-circle-check: \\e596;\n$fa-var-person-arrow-down-to-line: \\e538;\n$fa-var-voicemail: \\f897;\n$fa-var-fan: \\f863;\n$fa-var-person-walking-luggage: \\e554;\n$fa-var-up-down: \\f338;\n$fa-var-arrows-alt-v: \\f338;\n$fa-var-cloud-moon-rain: \\f73c;\n$fa-var-calendar: \\f133;\n$fa-var-trailer: \\e041;\n$fa-var-bahai: \\f666;\n$fa-var-haykal: \\f666;\n$fa-var-sd-card: \\f7c2;\n$fa-var-dragon: \\f6d5;\n$fa-var-shoe-prints: \\f54b;\n$fa-var-circle-plus: \\f055;\n$fa-var-plus-circle: \\f055;\n$fa-var-face-grin-tongue-wink: \\f58b;\n$fa-var-grin-tongue-wink: \\f58b;\n$fa-var-hand-holding: \\f4bd;\n$fa-var-plug-circle-exclamation: \\e55d;\n$fa-var-link-slash: \\f127;\n$fa-var-chain-broken: \\f127;\n$fa-var-chain-slash: \\f127;\n$fa-var-unlink: \\f127;\n$fa-var-clone: \\f24d;\n$fa-var-person-walking-arrow-loop-left: \\e551;\n$fa-var-arrow-up-z-a: \\f882;\n$fa-var-sort-alpha-up-alt: \\f882;\n$fa-var-fire-flame-curved: \\f7e4;\n$fa-var-fire-alt: \\f7e4;\n$fa-var-tornado: \\f76f;\n$fa-var-file-circle-plus: \\e494;\n$fa-var-book-quran: \\f687;\n$fa-var-quran: \\f687;\n$fa-var-anchor: \\f13d;\n$fa-var-border-all: \\f84c;\n$fa-var-face-angry: \\f556;\n$fa-var-angry: \\f556;\n$fa-var-cookie-bite: \\f564;\n$fa-var-arrow-trend-down: \\e097;\n$fa-var-rss: \\f09e;\n$fa-var-feed: \\f09e;\n$fa-var-draw-polygon: \\f5ee;\n$fa-var-scale-balanced: \\f24e;\n$fa-var-balance-scale: \\f24e;\n$fa-var-gauge-simple-high: \\f62a;\n$fa-var-tachometer: \\f62a;\n$fa-var-tachometer-fast: \\f62a;\n$fa-var-shower: \\f2cc;\n$fa-var-desktop: \\f390;\n$fa-var-desktop-alt: \\f390;\n$fa-var-m: \\4d;\n$fa-var-table-list: \\f00b;\n$fa-var-th-list: \\f00b;\n$fa-var-comment-sms: \\f7cd;\n$fa-var-sms: \\f7cd;\n$fa-var-book: \\f02d;\n$fa-var-user-plus: \\f234;\n$fa-var-check: \\f00c;\n$fa-var-battery-three-quarters: \\f241;\n$fa-var-battery-4: \\f241;\n$fa-var-house-circle-check: \\e509;\n$fa-var-angle-left: \\f104;\n$fa-var-diagram-successor: \\e47a;\n$fa-var-truck-arrow-right: \\e58b;\n$fa-var-arrows-split-up-and-left: \\e4bc;\n$fa-var-hand-fist: \\f6de;\n$fa-var-fist-raised: \\f6de;\n$fa-var-cloud-moon: \\f6c3;\n$fa-var-briefcase: \\f0b1;\n$fa-var-person-falling: \\e546;\n$fa-var-image-portrait: \\f3e0;\n$fa-var-portrait: \\f3e0;\n$fa-var-user-tag: \\f507;\n$fa-var-rug: \\e569;\n$fa-var-earth-europe: \\f7a2;\n$fa-var-globe-europe: \\f7a2;\n$fa-var-cart-flatbed-suitcase: \\f59d;\n$fa-var-luggage-cart: \\f59d;\n$fa-var-rectangle-xmark: \\f410;\n$fa-var-rectangle-times: \\f410;\n$fa-var-times-rectangle: \\f410;\n$fa-var-window-close: \\f410;\n$fa-var-baht-sign: \\e0ac;\n$fa-var-book-open: \\f518;\n$fa-var-book-journal-whills: \\f66a;\n$fa-var-journal-whills: \\f66a;\n$fa-var-handcuffs: \\e4f8;\n$fa-var-triangle-exclamation: \\f071;\n$fa-var-exclamation-triangle: \\f071;\n$fa-var-warning: \\f071;\n$fa-var-database: \\f1c0;\n$fa-var-share: \\f064;\n$fa-var-mail-forward: \\f064;\n$fa-var-bottle-droplet: \\e4c4;\n$fa-var-mask-face: \\e1d7;\n$fa-var-hill-rockslide: \\e508;\n$fa-var-right-left: \\f362;\n$fa-var-exchange-alt: \\f362;\n$fa-var-paper-plane: \\f1d8;\n$fa-var-road-circle-exclamation: \\e565;\n$fa-var-dungeon: \\f6d9;\n$fa-var-align-right: \\f038;\n$fa-var-money-bill-1-wave: \\f53b;\n$fa-var-money-bill-wave-alt: \\f53b;\n$fa-var-life-ring: \\f1cd;\n$fa-var-hands: \\f2a7;\n$fa-var-sign-language: \\f2a7;\n$fa-var-signing: \\f2a7;\n$fa-var-calendar-day: \\f783;\n$fa-var-water-ladder: \\f5c5;\n$fa-var-ladder-water: \\f5c5;\n$fa-var-swimming-pool: \\f5c5;\n$fa-var-arrows-up-down: \\f07d;\n$fa-var-arrows-v: \\f07d;\n$fa-var-face-grimace: \\f57f;\n$fa-var-grimace: \\f57f;\n$fa-var-wheelchair-move: \\e2ce;\n$fa-var-wheelchair-alt: \\e2ce;\n$fa-var-turn-down: \\f3be;\n$fa-var-level-down-alt: \\f3be;\n$fa-var-person-walking-arrow-right: \\e552;\n$fa-var-square-envelope: \\f199;\n$fa-var-envelope-square: \\f199;\n$fa-var-dice: \\f522;\n$fa-var-bowling-ball: \\f436;\n$fa-var-brain: \\f5dc;\n$fa-var-bandage: \\f462;\n$fa-var-band-aid: \\f462;\n$fa-var-calendar-minus: \\f272;\n$fa-var-circle-xmark: \\f057;\n$fa-var-times-circle: \\f057;\n$fa-var-xmark-circle: \\f057;\n$fa-var-gifts: \\f79c;\n$fa-var-hotel: \\f594;\n$fa-var-earth-asia: \\f57e;\n$fa-var-globe-asia: \\f57e;\n$fa-var-id-card-clip: \\f47f;\n$fa-var-id-card-alt: \\f47f;\n$fa-var-magnifying-glass-plus: \\f00e;\n$fa-var-search-plus: \\f00e;\n$fa-var-thumbs-up: \\f164;\n$fa-var-user-clock: \\f4fd;\n$fa-var-hand-dots: \\f461;\n$fa-var-allergies: \\f461;\n$fa-var-file-invoice: \\f570;\n$fa-var-window-minimize: \\f2d1;\n$fa-var-mug-saucer: \\f0f4;\n$fa-var-coffee: \\f0f4;\n$fa-var-brush: \\f55d;\n$fa-var-file-half-dashed: \\e698;\n$fa-var-mask: \\f6fa;\n$fa-var-magnifying-glass-minus: \\f010;\n$fa-var-search-minus: \\f010;\n$fa-var-ruler-vertical: \\f548;\n$fa-var-user-large: \\f406;\n$fa-var-user-alt: \\f406;\n$fa-var-train-tram: \\e5b4;\n$fa-var-user-nurse: \\f82f;\n$fa-var-syringe: \\f48e;\n$fa-var-cloud-sun: \\f6c4;\n$fa-var-stopwatch-20: \\e06f;\n$fa-var-square-full: \\f45c;\n$fa-var-magnet: \\f076;\n$fa-var-jar: \\e516;\n$fa-var-note-sticky: \\f249;\n$fa-var-sticky-note: \\f249;\n$fa-var-bug-slash: \\e490;\n$fa-var-arrow-up-from-water-pump: \\e4b6;\n$fa-var-bone: \\f5d7;\n$fa-var-table-cells-row-unlock: \\e691;\n$fa-var-user-injured: \\f728;\n$fa-var-face-sad-tear: \\f5b4;\n$fa-var-sad-tear: \\f5b4;\n$fa-var-plane: \\f072;\n$fa-var-tent-arrows-down: \\e581;\n$fa-var-exclamation: \\21;\n$fa-var-arrows-spin: \\e4bb;\n$fa-var-print: \\f02f;\n$fa-var-turkish-lira-sign: \\e2bb;\n$fa-var-try: \\e2bb;\n$fa-var-turkish-lira: \\e2bb;\n$fa-var-dollar-sign: \\24;\n$fa-var-dollar: \\24;\n$fa-var-usd: \\24;\n$fa-var-x: \\58;\n$fa-var-magnifying-glass-dollar: \\f688;\n$fa-var-search-dollar: \\f688;\n$fa-var-users-gear: \\f509;\n$fa-var-users-cog: \\f509;\n$fa-var-person-military-pointing: \\e54a;\n$fa-var-building-columns: \\f19c;\n$fa-var-bank: \\f19c;\n$fa-var-institution: \\f19c;\n$fa-var-museum: \\f19c;\n$fa-var-university: \\f19c;\n$fa-var-umbrella: \\f0e9;\n$fa-var-trowel: \\e589;\n$fa-var-d: \\44;\n$fa-var-stapler: \\e5af;\n$fa-var-masks-theater: \\f630;\n$fa-var-theater-masks: \\f630;\n$fa-var-kip-sign: \\e1c4;\n$fa-var-hand-point-left: \\f0a5;\n$fa-var-handshake-simple: \\f4c6;\n$fa-var-handshake-alt: \\f4c6;\n$fa-var-jet-fighter: \\f0fb;\n$fa-var-fighter-jet: \\f0fb;\n$fa-var-square-share-nodes: \\f1e1;\n$fa-var-share-alt-square: \\f1e1;\n$fa-var-barcode: \\f02a;\n$fa-var-plus-minus: \\e43c;\n$fa-var-video: \\f03d;\n$fa-var-video-camera: \\f03d;\n$fa-var-graduation-cap: \\f19d;\n$fa-var-mortar-board: \\f19d;\n$fa-var-hand-holding-medical: \\e05c;\n$fa-var-person-circle-check: \\e53e;\n$fa-var-turn-up: \\f3bf;\n$fa-var-level-up-alt: \\f3bf;\n\n$fa-var-monero: \\f3d0;\n$fa-var-hooli: \\f427;\n$fa-var-yelp: \\f1e9;\n$fa-var-cc-visa: \\f1f0;\n$fa-var-lastfm: \\f202;\n$fa-var-shopware: \\f5b5;\n$fa-var-creative-commons-nc: \\f4e8;\n$fa-var-aws: \\f375;\n$fa-var-redhat: \\f7bc;\n$fa-var-yoast: \\f2b1;\n$fa-var-cloudflare: \\e07d;\n$fa-var-ups: \\f7e0;\n$fa-var-pixiv: \\e640;\n$fa-var-wpexplorer: \\f2de;\n$fa-var-dyalog: \\f399;\n$fa-var-bity: \\f37a;\n$fa-var-stackpath: \\f842;\n$fa-var-buysellads: \\f20d;\n$fa-var-first-order: \\f2b0;\n$fa-var-modx: \\f285;\n$fa-var-guilded: \\e07e;\n$fa-var-vnv: \\f40b;\n$fa-var-square-js: \\f3b9;\n$fa-var-js-square: \\f3b9;\n$fa-var-microsoft: \\f3ca;\n$fa-var-qq: \\f1d6;\n$fa-var-orcid: \\f8d2;\n$fa-var-java: \\f4e4;\n$fa-var-invision: \\f7b0;\n$fa-var-creative-commons-pd-alt: \\f4ed;\n$fa-var-centercode: \\f380;\n$fa-var-glide-g: \\f2a6;\n$fa-var-drupal: \\f1a9;\n$fa-var-jxl: \\e67b;\n$fa-var-dart-lang: \\e693;\n$fa-var-hire-a-helper: \\f3b0;\n$fa-var-creative-commons-by: \\f4e7;\n$fa-var-unity: \\e049;\n$fa-var-whmcs: \\f40d;\n$fa-var-rocketchat: \\f3e8;\n$fa-var-vk: \\f189;\n$fa-var-untappd: \\f405;\n$fa-var-mailchimp: \\f59e;\n$fa-var-css3-alt: \\f38b;\n$fa-var-square-reddit: \\f1a2;\n$fa-var-reddit-square: \\f1a2;\n$fa-var-vimeo-v: \\f27d;\n$fa-var-contao: \\f26d;\n$fa-var-square-font-awesome: \\e5ad;\n$fa-var-deskpro: \\f38f;\n$fa-var-brave: \\e63c;\n$fa-var-sistrix: \\f3ee;\n$fa-var-square-instagram: \\e055;\n$fa-var-instagram-square: \\e055;\n$fa-var-battle-net: \\f835;\n$fa-var-the-red-yeti: \\f69d;\n$fa-var-square-hacker-news: \\f3af;\n$fa-var-hacker-news-square: \\f3af;\n$fa-var-edge: \\f282;\n$fa-var-threads: \\e618;\n$fa-var-napster: \\f3d2;\n$fa-var-square-snapchat: \\f2ad;\n$fa-var-snapchat-square: \\f2ad;\n$fa-var-google-plus-g: \\f0d5;\n$fa-var-artstation: \\f77a;\n$fa-var-markdown: \\f60f;\n$fa-var-sourcetree: \\f7d3;\n$fa-var-google-plus: \\f2b3;\n$fa-var-diaspora: \\f791;\n$fa-var-foursquare: \\f180;\n$fa-var-stack-overflow: \\f16c;\n$fa-var-github-alt: \\f113;\n$fa-var-phoenix-squadron: \\f511;\n$fa-var-pagelines: \\f18c;\n$fa-var-algolia: \\f36c;\n$fa-var-red-river: \\f3e3;\n$fa-var-creative-commons-sa: \\f4ef;\n$fa-var-safari: \\f267;\n$fa-var-google: \\f1a0;\n$fa-var-square-font-awesome-stroke: \\f35c;\n$fa-var-font-awesome-alt: \\f35c;\n$fa-var-atlassian: \\f77b;\n$fa-var-linkedin-in: \\f0e1;\n$fa-var-digital-ocean: \\f391;\n$fa-var-nimblr: \\f5a8;\n$fa-var-chromecast: \\f838;\n$fa-var-evernote: \\f839;\n$fa-var-hacker-news: \\f1d4;\n$fa-var-creative-commons-sampling: \\f4f0;\n$fa-var-adversal: \\f36a;\n$fa-var-creative-commons: \\f25e;\n$fa-var-watchman-monitoring: \\e087;\n$fa-var-fonticons: \\f280;\n$fa-var-weixin: \\f1d7;\n$fa-var-shirtsinbulk: \\f214;\n$fa-var-codepen: \\f1cb;\n$fa-var-git-alt: \\f841;\n$fa-var-lyft: \\f3c3;\n$fa-var-rev: \\f5b2;\n$fa-var-windows: \\f17a;\n$fa-var-wizards-of-the-coast: \\f730;\n$fa-var-square-viadeo: \\f2aa;\n$fa-var-viadeo-square: \\f2aa;\n$fa-var-meetup: \\f2e0;\n$fa-var-centos: \\f789;\n$fa-var-adn: \\f170;\n$fa-var-cloudsmith: \\f384;\n$fa-var-opensuse: \\e62b;\n$fa-var-pied-piper-alt: \\f1a8;\n$fa-var-square-dribbble: \\f397;\n$fa-var-dribbble-square: \\f397;\n$fa-var-codiepie: \\f284;\n$fa-var-node: \\f419;\n$fa-var-mix: \\f3cb;\n$fa-var-steam: \\f1b6;\n$fa-var-cc-apple-pay: \\f416;\n$fa-var-scribd: \\f28a;\n$fa-var-debian: \\e60b;\n$fa-var-openid: \\f19b;\n$fa-var-instalod: \\e081;\n$fa-var-files-pinwheel: \\e69f;\n$fa-var-expeditedssl: \\f23e;\n$fa-var-sellcast: \\f2da;\n$fa-var-square-twitter: \\f081;\n$fa-var-twitter-square: \\f081;\n$fa-var-r-project: \\f4f7;\n$fa-var-delicious: \\f1a5;\n$fa-var-freebsd: \\f3a4;\n$fa-var-vuejs: \\f41f;\n$fa-var-accusoft: \\f369;\n$fa-var-ioxhost: \\f208;\n$fa-var-fonticons-fi: \\f3a2;\n$fa-var-app-store: \\f36f;\n$fa-var-cc-mastercard: \\f1f1;\n$fa-var-itunes-note: \\f3b5;\n$fa-var-golang: \\e40f;\n$fa-var-kickstarter: \\f3bb;\n$fa-var-square-kickstarter: \\f3bb;\n$fa-var-grav: \\f2d6;\n$fa-var-weibo: \\f18a;\n$fa-var-uncharted: \\e084;\n$fa-var-firstdraft: \\f3a1;\n$fa-var-square-youtube: \\f431;\n$fa-var-youtube-square: \\f431;\n$fa-var-wikipedia-w: \\f266;\n$fa-var-wpressr: \\f3e4;\n$fa-var-rendact: \\f3e4;\n$fa-var-angellist: \\f209;\n$fa-var-galactic-republic: \\f50c;\n$fa-var-nfc-directional: \\e530;\n$fa-var-skype: \\f17e;\n$fa-var-joget: \\f3b7;\n$fa-var-fedora: \\f798;\n$fa-var-stripe-s: \\f42a;\n$fa-var-meta: \\e49b;\n$fa-var-laravel: \\f3bd;\n$fa-var-hotjar: \\f3b1;\n$fa-var-bluetooth-b: \\f294;\n$fa-var-square-letterboxd: \\e62e;\n$fa-var-sticker-mule: \\f3f7;\n$fa-var-creative-commons-zero: \\f4f3;\n$fa-var-hips: \\f452;\n$fa-var-css: \\e6a2;\n$fa-var-behance: \\f1b4;\n$fa-var-reddit: \\f1a1;\n$fa-var-discord: \\f392;\n$fa-var-chrome: \\f268;\n$fa-var-app-store-ios: \\f370;\n$fa-var-cc-discover: \\f1f2;\n$fa-var-wpbeginner: \\f297;\n$fa-var-confluence: \\f78d;\n$fa-var-shoelace: \\e60c;\n$fa-var-mdb: \\f8ca;\n$fa-var-dochub: \\f394;\n$fa-var-accessible-icon: \\f368;\n$fa-var-ebay: \\f4f4;\n$fa-var-amazon: \\f270;\n$fa-var-unsplash: \\e07c;\n$fa-var-yarn: \\f7e3;\n$fa-var-square-steam: \\f1b7;\n$fa-var-steam-square: \\f1b7;\n$fa-var-500px: \\f26e;\n$fa-var-square-vimeo: \\f194;\n$fa-var-vimeo-square: \\f194;\n$fa-var-asymmetrik: \\f372;\n$fa-var-font-awesome: \\f2b4;\n$fa-var-font-awesome-flag: \\f2b4;\n$fa-var-font-awesome-logo-full: \\f2b4;\n$fa-var-gratipay: \\f184;\n$fa-var-apple: \\f179;\n$fa-var-hive: \\e07f;\n$fa-var-gitkraken: \\f3a6;\n$fa-var-keybase: \\f4f5;\n$fa-var-apple-pay: \\f415;\n$fa-var-padlet: \\e4a0;\n$fa-var-amazon-pay: \\f42c;\n$fa-var-square-github: \\f092;\n$fa-var-github-square: \\f092;\n$fa-var-stumbleupon: \\f1a4;\n$fa-var-fedex: \\f797;\n$fa-var-phoenix-framework: \\f3dc;\n$fa-var-shopify: \\e057;\n$fa-var-neos: \\f612;\n$fa-var-square-threads: \\e619;\n$fa-var-hackerrank: \\f5f7;\n$fa-var-researchgate: \\f4f8;\n$fa-var-swift: \\f8e1;\n$fa-var-angular: \\f420;\n$fa-var-speakap: \\f3f3;\n$fa-var-angrycreative: \\f36e;\n$fa-var-y-combinator: \\f23b;\n$fa-var-empire: \\f1d1;\n$fa-var-envira: \\f299;\n$fa-var-google-scholar: \\e63b;\n$fa-var-square-gitlab: \\e5ae;\n$fa-var-gitlab-square: \\e5ae;\n$fa-var-studiovinari: \\f3f8;\n$fa-var-pied-piper: \\f2ae;\n$fa-var-wordpress: \\f19a;\n$fa-var-product-hunt: \\f288;\n$fa-var-firefox: \\f269;\n$fa-var-linode: \\f2b8;\n$fa-var-goodreads: \\f3a8;\n$fa-var-square-odnoklassniki: \\f264;\n$fa-var-odnoklassniki-square: \\f264;\n$fa-var-jsfiddle: \\f1cc;\n$fa-var-sith: \\f512;\n$fa-var-themeisle: \\f2b2;\n$fa-var-page4: \\f3d7;\n$fa-var-hashnode: \\e499;\n$fa-var-react: \\f41b;\n$fa-var-cc-paypal: \\f1f4;\n$fa-var-squarespace: \\f5be;\n$fa-var-cc-stripe: \\f1f5;\n$fa-var-creative-commons-share: \\f4f2;\n$fa-var-bitcoin: \\f379;\n$fa-var-keycdn: \\f3ba;\n$fa-var-opera: \\f26a;\n$fa-var-itch-io: \\f83a;\n$fa-var-umbraco: \\f8e8;\n$fa-var-galactic-senate: \\f50d;\n$fa-var-ubuntu: \\f7df;\n$fa-var-draft2digital: \\f396;\n$fa-var-stripe: \\f429;\n$fa-var-houzz: \\f27c;\n$fa-var-gg: \\f260;\n$fa-var-dhl: \\f790;\n$fa-var-square-pinterest: \\f0d3;\n$fa-var-pinterest-square: \\f0d3;\n$fa-var-xing: \\f168;\n$fa-var-blackberry: \\f37b;\n$fa-var-creative-commons-pd: \\f4ec;\n$fa-var-playstation: \\f3df;\n$fa-var-quinscape: \\f459;\n$fa-var-less: \\f41d;\n$fa-var-blogger-b: \\f37d;\n$fa-var-opencart: \\f23d;\n$fa-var-vine: \\f1ca;\n$fa-var-signal-messenger: \\e663;\n$fa-var-paypal: \\f1ed;\n$fa-var-gitlab: \\f296;\n$fa-var-typo3: \\f42b;\n$fa-var-reddit-alien: \\f281;\n$fa-var-yahoo: \\f19e;\n$fa-var-dailymotion: \\e052;\n$fa-var-affiliatetheme: \\f36b;\n$fa-var-pied-piper-pp: \\f1a7;\n$fa-var-bootstrap: \\f836;\n$fa-var-odnoklassniki: \\f263;\n$fa-var-nfc-symbol: \\e531;\n$fa-var-mintbit: \\e62f;\n$fa-var-ethereum: \\f42e;\n$fa-var-speaker-deck: \\f83c;\n$fa-var-creative-commons-nc-eu: \\f4e9;\n$fa-var-patreon: \\f3d9;\n$fa-var-avianex: \\f374;\n$fa-var-ello: \\f5f1;\n$fa-var-gofore: \\f3a7;\n$fa-var-bimobject: \\f378;\n$fa-var-brave-reverse: \\e63d;\n$fa-var-facebook-f: \\f39e;\n$fa-var-square-google-plus: \\f0d4;\n$fa-var-google-plus-square: \\f0d4;\n$fa-var-web-awesome: \\e682;\n$fa-var-mandalorian: \\f50f;\n$fa-var-first-order-alt: \\f50a;\n$fa-var-osi: \\f41a;\n$fa-var-google-wallet: \\f1ee;\n$fa-var-d-and-d-beyond: \\f6ca;\n$fa-var-periscope: \\f3da;\n$fa-var-fulcrum: \\f50b;\n$fa-var-cloudscale: \\f383;\n$fa-var-forumbee: \\f211;\n$fa-var-mizuni: \\f3cc;\n$fa-var-schlix: \\f3ea;\n$fa-var-square-xing: \\f169;\n$fa-var-xing-square: \\f169;\n$fa-var-bandcamp: \\f2d5;\n$fa-var-wpforms: \\f298;\n$fa-var-cloudversify: \\f385;\n$fa-var-usps: \\f7e1;\n$fa-var-megaport: \\f5a3;\n$fa-var-magento: \\f3c4;\n$fa-var-spotify: \\f1bc;\n$fa-var-optin-monster: \\f23c;\n$fa-var-fly: \\f417;\n$fa-var-square-bluesky: \\e6a3;\n$fa-var-aviato: \\f421;\n$fa-var-itunes: \\f3b4;\n$fa-var-cuttlefish: \\f38c;\n$fa-var-blogger: \\f37c;\n$fa-var-flickr: \\f16e;\n$fa-var-viber: \\f409;\n$fa-var-soundcloud: \\f1be;\n$fa-var-digg: \\f1a6;\n$fa-var-tencent-weibo: \\f1d5;\n$fa-var-letterboxd: \\e62d;\n$fa-var-symfony: \\f83d;\n$fa-var-maxcdn: \\f136;\n$fa-var-etsy: \\f2d7;\n$fa-var-facebook-messenger: \\f39f;\n$fa-var-audible: \\f373;\n$fa-var-think-peaks: \\f731;\n$fa-var-bilibili: \\e3d9;\n$fa-var-erlang: \\f39d;\n$fa-var-x-twitter: \\e61b;\n$fa-var-cotton-bureau: \\f89e;\n$fa-var-dashcube: \\f210;\n$fa-var-42-group: \\e080;\n$fa-var-innosoft: \\e080;\n$fa-var-stack-exchange: \\f18d;\n$fa-var-elementor: \\f430;\n$fa-var-square-pied-piper: \\e01e;\n$fa-var-pied-piper-square: \\e01e;\n$fa-var-creative-commons-nd: \\f4eb;\n$fa-var-palfed: \\f3d8;\n$fa-var-superpowers: \\f2dd;\n$fa-var-resolving: \\f3e7;\n$fa-var-xbox: \\f412;\n$fa-var-square-web-awesome-stroke: \\e684;\n$fa-var-searchengin: \\f3eb;\n$fa-var-tiktok: \\e07b;\n$fa-var-square-facebook: \\f082;\n$fa-var-facebook-square: \\f082;\n$fa-var-renren: \\f18b;\n$fa-var-linux: \\f17c;\n$fa-var-glide: \\f2a5;\n$fa-var-linkedin: \\f08c;\n$fa-var-hubspot: \\f3b2;\n$fa-var-deploydog: \\f38e;\n$fa-var-twitch: \\f1e8;\n$fa-var-flutter: \\e694;\n$fa-var-ravelry: \\f2d9;\n$fa-var-mixer: \\e056;\n$fa-var-square-lastfm: \\f203;\n$fa-var-lastfm-square: \\f203;\n$fa-var-vimeo: \\f40a;\n$fa-var-mendeley: \\f7b3;\n$fa-var-uniregistry: \\f404;\n$fa-var-figma: \\f799;\n$fa-var-creative-commons-remix: \\f4ee;\n$fa-var-cc-amazon-pay: \\f42d;\n$fa-var-dropbox: \\f16b;\n$fa-var-instagram: \\f16d;\n$fa-var-cmplid: \\e360;\n$fa-var-upwork: \\e641;\n$fa-var-facebook: \\f09a;\n$fa-var-gripfire: \\f3ac;\n$fa-var-jedi-order: \\f50e;\n$fa-var-uikit: \\f403;\n$fa-var-fort-awesome-alt: \\f3a3;\n$fa-var-phabricator: \\f3db;\n$fa-var-ussunnah: \\f407;\n$fa-var-earlybirds: \\f39a;\n$fa-var-trade-federation: \\f513;\n$fa-var-autoprefixer: \\f41c;\n$fa-var-whatsapp: \\f232;\n$fa-var-square-upwork: \\e67c;\n$fa-var-slideshare: \\f1e7;\n$fa-var-google-play: \\f3ab;\n$fa-var-viadeo: \\f2a9;\n$fa-var-line: \\f3c0;\n$fa-var-google-drive: \\f3aa;\n$fa-var-servicestack: \\f3ec;\n$fa-var-simplybuilt: \\f215;\n$fa-var-bitbucket: \\f171;\n$fa-var-imdb: \\f2d8;\n$fa-var-deezer: \\e077;\n$fa-var-raspberry-pi: \\f7bb;\n$fa-var-jira: \\f7b1;\n$fa-var-docker: \\f395;\n$fa-var-screenpal: \\e570;\n$fa-var-bluetooth: \\f293;\n$fa-var-gitter: \\f426;\n$fa-var-d-and-d: \\f38d;\n$fa-var-microblog: \\e01a;\n$fa-var-cc-diners-club: \\f24c;\n$fa-var-gg-circle: \\f261;\n$fa-var-pied-piper-hat: \\f4e5;\n$fa-var-kickstarter-k: \\f3bc;\n$fa-var-yandex: \\f413;\n$fa-var-readme: \\f4d5;\n$fa-var-html5: \\f13b;\n$fa-var-sellsy: \\f213;\n$fa-var-square-web-awesome: \\e683;\n$fa-var-sass: \\f41e;\n$fa-var-wirsindhandwerk: \\e2d0;\n$fa-var-wsh: \\e2d0;\n$fa-var-buromobelexperte: \\f37f;\n$fa-var-salesforce: \\f83b;\n$fa-var-octopus-deploy: \\e082;\n$fa-var-medapps: \\f3c6;\n$fa-var-ns8: \\f3d5;\n$fa-var-pinterest-p: \\f231;\n$fa-var-apper: \\f371;\n$fa-var-fort-awesome: \\f286;\n$fa-var-waze: \\f83f;\n$fa-var-bluesky: \\e671;\n$fa-var-cc-jcb: \\f24b;\n$fa-var-snapchat: \\f2ab;\n$fa-var-snapchat-ghost: \\f2ab;\n$fa-var-fantasy-flight-games: \\f6dc;\n$fa-var-rust: \\e07a;\n$fa-var-wix: \\f5cf;\n$fa-var-square-behance: \\f1b5;\n$fa-var-behance-square: \\f1b5;\n$fa-var-supple: \\f3f9;\n$fa-var-webflow: \\e65c;\n$fa-var-rebel: \\f1d0;\n$fa-var-css3: \\f13c;\n$fa-var-staylinked: \\f3f5;\n$fa-var-kaggle: \\f5fa;\n$fa-var-space-awesome: \\e5ac;\n$fa-var-deviantart: \\f1bd;\n$fa-var-cpanel: \\f388;\n$fa-var-goodreads-g: \\f3a9;\n$fa-var-square-git: \\f1d2;\n$fa-var-git-square: \\f1d2;\n$fa-var-square-tumblr: \\f174;\n$fa-var-tumblr-square: \\f174;\n$fa-var-trello: \\f181;\n$fa-var-creative-commons-nc-jp: \\f4ea;\n$fa-var-get-pocket: \\f265;\n$fa-var-perbyte: \\e083;\n$fa-var-grunt: \\f3ad;\n$fa-var-weebly: \\f5cc;\n$fa-var-connectdevelop: \\f20e;\n$fa-var-leanpub: \\f212;\n$fa-var-black-tie: \\f27e;\n$fa-var-themeco: \\f5c6;\n$fa-var-python: \\f3e2;\n$fa-var-android: \\f17b;\n$fa-var-bots: \\e340;\n$fa-var-free-code-camp: \\f2c5;\n$fa-var-hornbill: \\f592;\n$fa-var-js: \\f3b8;\n$fa-var-ideal: \\e013;\n$fa-var-git: \\f1d3;\n$fa-var-dev: \\f6cc;\n$fa-var-sketch: \\f7c6;\n$fa-var-yandex-international: \\f414;\n$fa-var-cc-amex: \\f1f3;\n$fa-var-uber: \\f402;\n$fa-var-github: \\f09b;\n$fa-var-php: \\f457;\n$fa-var-alipay: \\f642;\n$fa-var-youtube: \\f167;\n$fa-var-skyatlas: \\f216;\n$fa-var-firefox-browser: \\e007;\n$fa-var-replyd: \\f3e6;\n$fa-var-suse: \\f7d6;\n$fa-var-jenkins: \\f3b6;\n$fa-var-twitter: \\f099;\n$fa-var-rockrms: \\f3e9;\n$fa-var-pinterest: \\f0d2;\n$fa-var-buffer: \\f837;\n$fa-var-npm: \\f3d4;\n$fa-var-yammer: \\f840;\n$fa-var-btc: \\f15a;\n$fa-var-dribbble: \\f17d;\n$fa-var-stumbleupon-circle: \\f1a3;\n$fa-var-internet-explorer: \\f26b;\n$fa-var-stubber: \\e5c7;\n$fa-var-telegram: \\f2c6;\n$fa-var-telegram-plane: \\f2c6;\n$fa-var-old-republic: \\f510;\n$fa-var-odysee: \\e5c6;\n$fa-var-square-whatsapp: \\f40c;\n$fa-var-whatsapp-square: \\f40c;\n$fa-var-node-js: \\f3d3;\n$fa-var-edge-legacy: \\e078;\n$fa-var-slack: \\f198;\n$fa-var-slack-hash: \\f198;\n$fa-var-medrt: \\f3c8;\n$fa-var-usb: \\f287;\n$fa-var-tumblr: \\f173;\n$fa-var-vaadin: \\f408;\n$fa-var-quora: \\f2c4;\n$fa-var-square-x-twitter: \\e61a;\n$fa-var-reacteurope: \\f75d;\n$fa-var-medium: \\f23a;\n$fa-var-medium-m: \\f23a;\n$fa-var-amilia: \\f36d;\n$fa-var-mixcloud: \\f289;\n$fa-var-flipboard: \\f44d;\n$fa-var-viacoin: \\f237;\n$fa-var-critical-role: \\f6c9;\n$fa-var-sitrox: \\e44a;\n$fa-var-discourse: \\f393;\n$fa-var-joomla: \\f1aa;\n$fa-var-mastodon: \\f4f6;\n$fa-var-airbnb: \\f834;\n$fa-var-wolf-pack-battalion: \\f514;\n$fa-var-buy-n-large: \\f8a6;\n$fa-var-gulp: \\f3ae;\n$fa-var-creative-commons-sampling-plus: \\f4f1;\n$fa-var-strava: \\f428;\n$fa-var-ember: \\f423;\n$fa-var-canadian-maple-leaf: \\f785;\n$fa-var-teamspeak: \\f4f9;\n$fa-var-pushed: \\f3e1;\n$fa-var-wordpress-simple: \\f411;\n$fa-var-nutritionix: \\f3d6;\n$fa-var-wodu: \\e088;\n$fa-var-google-pay: \\e079;\n$fa-var-intercom: \\f7af;\n$fa-var-zhihu: \\f63f;\n$fa-var-korvue: \\f42f;\n$fa-var-pix: \\e43a;\n$fa-var-steam-symbol: \\f3f6;\n\n$fa-icons: (\n \"0\": $fa-var-0,\n \"1\": $fa-var-1,\n \"2\": $fa-var-2,\n \"3\": $fa-var-3,\n \"4\": $fa-var-4,\n \"5\": $fa-var-5,\n \"6\": $fa-var-6,\n \"7\": $fa-var-7,\n \"8\": $fa-var-8,\n \"9\": $fa-var-9,\n \"fill-drip\": $fa-var-fill-drip,\n \"arrows-to-circle\": $fa-var-arrows-to-circle,\n \"circle-chevron-right\": $fa-var-circle-chevron-right,\n \"chevron-circle-right\": $fa-var-chevron-circle-right,\n \"at\": $fa-var-at,\n \"trash-can\": $fa-var-trash-can,\n \"trash-alt\": $fa-var-trash-alt,\n \"text-height\": $fa-var-text-height,\n \"user-xmark\": $fa-var-user-xmark,\n \"user-times\": $fa-var-user-times,\n \"stethoscope\": $fa-var-stethoscope,\n \"message\": $fa-var-message,\n \"comment-alt\": $fa-var-comment-alt,\n \"info\": $fa-var-info,\n \"down-left-and-up-right-to-center\": $fa-var-down-left-and-up-right-to-center,\n \"compress-alt\": $fa-var-compress-alt,\n \"explosion\": $fa-var-explosion,\n \"file-lines\": $fa-var-file-lines,\n \"file-alt\": $fa-var-file-alt,\n \"file-text\": $fa-var-file-text,\n \"wave-square\": $fa-var-wave-square,\n \"ring\": $fa-var-ring,\n \"building-un\": $fa-var-building-un,\n \"dice-three\": $fa-var-dice-three,\n \"calendar-days\": $fa-var-calendar-days,\n \"calendar-alt\": $fa-var-calendar-alt,\n \"anchor-circle-check\": $fa-var-anchor-circle-check,\n \"building-circle-arrow-right\": $fa-var-building-circle-arrow-right,\n \"volleyball\": $fa-var-volleyball,\n \"volleyball-ball\": $fa-var-volleyball-ball,\n \"arrows-up-to-line\": $fa-var-arrows-up-to-line,\n \"sort-down\": $fa-var-sort-down,\n \"sort-desc\": $fa-var-sort-desc,\n \"circle-minus\": $fa-var-circle-minus,\n \"minus-circle\": $fa-var-minus-circle,\n \"door-open\": $fa-var-door-open,\n \"right-from-bracket\": $fa-var-right-from-bracket,\n \"sign-out-alt\": $fa-var-sign-out-alt,\n \"atom\": $fa-var-atom,\n \"soap\": $fa-var-soap,\n \"icons\": $fa-var-icons,\n \"heart-music-camera-bolt\": $fa-var-heart-music-camera-bolt,\n \"microphone-lines-slash\": $fa-var-microphone-lines-slash,\n \"microphone-alt-slash\": $fa-var-microphone-alt-slash,\n \"bridge-circle-check\": $fa-var-bridge-circle-check,\n \"pump-medical\": $fa-var-pump-medical,\n \"fingerprint\": $fa-var-fingerprint,\n \"hand-point-right\": $fa-var-hand-point-right,\n \"magnifying-glass-location\": $fa-var-magnifying-glass-location,\n \"search-location\": $fa-var-search-location,\n \"forward-step\": $fa-var-forward-step,\n \"step-forward\": $fa-var-step-forward,\n \"face-smile-beam\": $fa-var-face-smile-beam,\n \"smile-beam\": $fa-var-smile-beam,\n \"flag-checkered\": $fa-var-flag-checkered,\n \"football\": $fa-var-football,\n \"football-ball\": $fa-var-football-ball,\n \"school-circle-exclamation\": $fa-var-school-circle-exclamation,\n \"crop\": $fa-var-crop,\n \"angles-down\": $fa-var-angles-down,\n \"angle-double-down\": $fa-var-angle-double-down,\n \"users-rectangle\": $fa-var-users-rectangle,\n \"people-roof\": $fa-var-people-roof,\n \"people-line\": $fa-var-people-line,\n \"beer-mug-empty\": $fa-var-beer-mug-empty,\n \"beer\": $fa-var-beer,\n \"diagram-predecessor\": $fa-var-diagram-predecessor,\n \"arrow-up-long\": $fa-var-arrow-up-long,\n \"long-arrow-up\": $fa-var-long-arrow-up,\n \"fire-flame-simple\": $fa-var-fire-flame-simple,\n \"burn\": $fa-var-burn,\n \"person\": $fa-var-person,\n \"male\": $fa-var-male,\n \"laptop\": $fa-var-laptop,\n \"file-csv\": $fa-var-file-csv,\n \"menorah\": $fa-var-menorah,\n \"truck-plane\": $fa-var-truck-plane,\n \"record-vinyl\": $fa-var-record-vinyl,\n \"face-grin-stars\": $fa-var-face-grin-stars,\n \"grin-stars\": $fa-var-grin-stars,\n \"bong\": $fa-var-bong,\n \"spaghetti-monster-flying\": $fa-var-spaghetti-monster-flying,\n \"pastafarianism\": $fa-var-pastafarianism,\n \"arrow-down-up-across-line\": $fa-var-arrow-down-up-across-line,\n \"spoon\": $fa-var-spoon,\n \"utensil-spoon\": $fa-var-utensil-spoon,\n \"jar-wheat\": $fa-var-jar-wheat,\n \"envelopes-bulk\": $fa-var-envelopes-bulk,\n \"mail-bulk\": $fa-var-mail-bulk,\n \"file-circle-exclamation\": $fa-var-file-circle-exclamation,\n \"circle-h\": $fa-var-circle-h,\n \"hospital-symbol\": $fa-var-hospital-symbol,\n \"pager\": $fa-var-pager,\n \"address-book\": $fa-var-address-book,\n \"contact-book\": $fa-var-contact-book,\n \"strikethrough\": $fa-var-strikethrough,\n \"k\": $fa-var-k,\n \"landmark-flag\": $fa-var-landmark-flag,\n \"pencil\": $fa-var-pencil,\n \"pencil-alt\": $fa-var-pencil-alt,\n \"backward\": $fa-var-backward,\n \"caret-right\": $fa-var-caret-right,\n \"comments\": $fa-var-comments,\n \"paste\": $fa-var-paste,\n \"file-clipboard\": $fa-var-file-clipboard,\n \"code-pull-request\": $fa-var-code-pull-request,\n \"clipboard-list\": $fa-var-clipboard-list,\n \"truck-ramp-box\": $fa-var-truck-ramp-box,\n \"truck-loading\": $fa-var-truck-loading,\n \"user-check\": $fa-var-user-check,\n \"vial-virus\": $fa-var-vial-virus,\n \"sheet-plastic\": $fa-var-sheet-plastic,\n \"blog\": $fa-var-blog,\n \"user-ninja\": $fa-var-user-ninja,\n \"person-arrow-up-from-line\": $fa-var-person-arrow-up-from-line,\n \"scroll-torah\": $fa-var-scroll-torah,\n \"torah\": $fa-var-torah,\n \"broom-ball\": $fa-var-broom-ball,\n \"quidditch\": $fa-var-quidditch,\n \"quidditch-broom-ball\": $fa-var-quidditch-broom-ball,\n \"toggle-off\": $fa-var-toggle-off,\n \"box-archive\": $fa-var-box-archive,\n \"archive\": $fa-var-archive,\n \"person-drowning\": $fa-var-person-drowning,\n \"arrow-down-9-1\": $fa-var-arrow-down-9-1,\n \"sort-numeric-desc\": $fa-var-sort-numeric-desc,\n \"sort-numeric-down-alt\": $fa-var-sort-numeric-down-alt,\n \"face-grin-tongue-squint\": $fa-var-face-grin-tongue-squint,\n \"grin-tongue-squint\": $fa-var-grin-tongue-squint,\n \"spray-can\": $fa-var-spray-can,\n \"truck-monster\": $fa-var-truck-monster,\n \"w\": $fa-var-w,\n \"earth-africa\": $fa-var-earth-africa,\n \"globe-africa\": $fa-var-globe-africa,\n \"rainbow\": $fa-var-rainbow,\n \"circle-notch\": $fa-var-circle-notch,\n \"tablet-screen-button\": $fa-var-tablet-screen-button,\n \"tablet-alt\": $fa-var-tablet-alt,\n \"paw\": $fa-var-paw,\n \"cloud\": $fa-var-cloud,\n \"trowel-bricks\": $fa-var-trowel-bricks,\n \"face-flushed\": $fa-var-face-flushed,\n \"flushed\": $fa-var-flushed,\n \"hospital-user\": $fa-var-hospital-user,\n \"tent-arrow-left-right\": $fa-var-tent-arrow-left-right,\n \"gavel\": $fa-var-gavel,\n \"legal\": $fa-var-legal,\n \"binoculars\": $fa-var-binoculars,\n \"microphone-slash\": $fa-var-microphone-slash,\n \"box-tissue\": $fa-var-box-tissue,\n \"motorcycle\": $fa-var-motorcycle,\n \"bell-concierge\": $fa-var-bell-concierge,\n \"concierge-bell\": $fa-var-concierge-bell,\n \"pen-ruler\": $fa-var-pen-ruler,\n \"pencil-ruler\": $fa-var-pencil-ruler,\n \"people-arrows\": $fa-var-people-arrows,\n \"people-arrows-left-right\": $fa-var-people-arrows-left-right,\n \"mars-and-venus-burst\": $fa-var-mars-and-venus-burst,\n \"square-caret-right\": $fa-var-square-caret-right,\n \"caret-square-right\": $fa-var-caret-square-right,\n \"scissors\": $fa-var-scissors,\n \"cut\": $fa-var-cut,\n \"sun-plant-wilt\": $fa-var-sun-plant-wilt,\n \"toilets-portable\": $fa-var-toilets-portable,\n \"hockey-puck\": $fa-var-hockey-puck,\n \"table\": $fa-var-table,\n \"magnifying-glass-arrow-right\": $fa-var-magnifying-glass-arrow-right,\n \"tachograph-digital\": $fa-var-tachograph-digital,\n \"digital-tachograph\": $fa-var-digital-tachograph,\n \"users-slash\": $fa-var-users-slash,\n \"clover\": $fa-var-clover,\n \"reply\": $fa-var-reply,\n \"mail-reply\": $fa-var-mail-reply,\n \"star-and-crescent\": $fa-var-star-and-crescent,\n \"house-fire\": $fa-var-house-fire,\n \"square-minus\": $fa-var-square-minus,\n \"minus-square\": $fa-var-minus-square,\n \"helicopter\": $fa-var-helicopter,\n \"compass\": $fa-var-compass,\n \"square-caret-down\": $fa-var-square-caret-down,\n \"caret-square-down\": $fa-var-caret-square-down,\n \"file-circle-question\": $fa-var-file-circle-question,\n \"laptop-code\": $fa-var-laptop-code,\n \"swatchbook\": $fa-var-swatchbook,\n \"prescription-bottle\": $fa-var-prescription-bottle,\n \"bars\": $fa-var-bars,\n \"navicon\": $fa-var-navicon,\n \"people-group\": $fa-var-people-group,\n \"hourglass-end\": $fa-var-hourglass-end,\n \"hourglass-3\": $fa-var-hourglass-3,\n \"heart-crack\": $fa-var-heart-crack,\n \"heart-broken\": $fa-var-heart-broken,\n \"square-up-right\": $fa-var-square-up-right,\n \"external-link-square-alt\": $fa-var-external-link-square-alt,\n \"face-kiss-beam\": $fa-var-face-kiss-beam,\n \"kiss-beam\": $fa-var-kiss-beam,\n \"film\": $fa-var-film,\n \"ruler-horizontal\": $fa-var-ruler-horizontal,\n \"people-robbery\": $fa-var-people-robbery,\n \"lightbulb\": $fa-var-lightbulb,\n \"caret-left\": $fa-var-caret-left,\n \"circle-exclamation\": $fa-var-circle-exclamation,\n \"exclamation-circle\": $fa-var-exclamation-circle,\n \"school-circle-xmark\": $fa-var-school-circle-xmark,\n \"arrow-right-from-bracket\": $fa-var-arrow-right-from-bracket,\n \"sign-out\": $fa-var-sign-out,\n \"circle-chevron-down\": $fa-var-circle-chevron-down,\n \"chevron-circle-down\": $fa-var-chevron-circle-down,\n \"unlock-keyhole\": $fa-var-unlock-keyhole,\n \"unlock-alt\": $fa-var-unlock-alt,\n \"cloud-showers-heavy\": $fa-var-cloud-showers-heavy,\n \"headphones-simple\": $fa-var-headphones-simple,\n \"headphones-alt\": $fa-var-headphones-alt,\n \"sitemap\": $fa-var-sitemap,\n \"circle-dollar-to-slot\": $fa-var-circle-dollar-to-slot,\n \"donate\": $fa-var-donate,\n \"memory\": $fa-var-memory,\n \"road-spikes\": $fa-var-road-spikes,\n \"fire-burner\": $fa-var-fire-burner,\n \"flag\": $fa-var-flag,\n \"hanukiah\": $fa-var-hanukiah,\n \"feather\": $fa-var-feather,\n \"volume-low\": $fa-var-volume-low,\n \"volume-down\": $fa-var-volume-down,\n \"comment-slash\": $fa-var-comment-slash,\n \"cloud-sun-rain\": $fa-var-cloud-sun-rain,\n \"compress\": $fa-var-compress,\n \"wheat-awn\": $fa-var-wheat-awn,\n \"wheat-alt\": $fa-var-wheat-alt,\n \"ankh\": $fa-var-ankh,\n \"hands-holding-child\": $fa-var-hands-holding-child,\n \"asterisk\": $fa-var-asterisk,\n \"square-check\": $fa-var-square-check,\n \"check-square\": $fa-var-check-square,\n \"peseta-sign\": $fa-var-peseta-sign,\n \"heading\": $fa-var-heading,\n \"header\": $fa-var-header,\n \"ghost\": $fa-var-ghost,\n \"list\": $fa-var-list,\n \"list-squares\": $fa-var-list-squares,\n \"square-phone-flip\": $fa-var-square-phone-flip,\n \"phone-square-alt\": $fa-var-phone-square-alt,\n \"cart-plus\": $fa-var-cart-plus,\n \"gamepad\": $fa-var-gamepad,\n \"circle-dot\": $fa-var-circle-dot,\n \"dot-circle\": $fa-var-dot-circle,\n \"face-dizzy\": $fa-var-face-dizzy,\n \"dizzy\": $fa-var-dizzy,\n \"egg\": $fa-var-egg,\n \"house-medical-circle-xmark\": $fa-var-house-medical-circle-xmark,\n \"campground\": $fa-var-campground,\n \"folder-plus\": $fa-var-folder-plus,\n \"futbol\": $fa-var-futbol,\n \"futbol-ball\": $fa-var-futbol-ball,\n \"soccer-ball\": $fa-var-soccer-ball,\n \"paintbrush\": $fa-var-paintbrush,\n \"paint-brush\": $fa-var-paint-brush,\n \"lock\": $fa-var-lock,\n \"gas-pump\": $fa-var-gas-pump,\n \"hot-tub-person\": $fa-var-hot-tub-person,\n \"hot-tub\": $fa-var-hot-tub,\n \"map-location\": $fa-var-map-location,\n \"map-marked\": $fa-var-map-marked,\n \"house-flood-water\": $fa-var-house-flood-water,\n \"tree\": $fa-var-tree,\n \"bridge-lock\": $fa-var-bridge-lock,\n \"sack-dollar\": $fa-var-sack-dollar,\n \"pen-to-square\": $fa-var-pen-to-square,\n \"edit\": $fa-var-edit,\n \"car-side\": $fa-var-car-side,\n \"share-nodes\": $fa-var-share-nodes,\n \"share-alt\": $fa-var-share-alt,\n \"heart-circle-minus\": $fa-var-heart-circle-minus,\n \"hourglass-half\": $fa-var-hourglass-half,\n \"hourglass-2\": $fa-var-hourglass-2,\n \"microscope\": $fa-var-microscope,\n \"sink\": $fa-var-sink,\n \"bag-shopping\": $fa-var-bag-shopping,\n \"shopping-bag\": $fa-var-shopping-bag,\n \"arrow-down-z-a\": $fa-var-arrow-down-z-a,\n \"sort-alpha-desc\": $fa-var-sort-alpha-desc,\n \"sort-alpha-down-alt\": $fa-var-sort-alpha-down-alt,\n \"mitten\": $fa-var-mitten,\n \"person-rays\": $fa-var-person-rays,\n \"users\": $fa-var-users,\n \"eye-slash\": $fa-var-eye-slash,\n \"flask-vial\": $fa-var-flask-vial,\n \"hand\": $fa-var-hand,\n \"hand-paper\": $fa-var-hand-paper,\n \"om\": $fa-var-om,\n \"worm\": $fa-var-worm,\n \"house-circle-xmark\": $fa-var-house-circle-xmark,\n \"plug\": $fa-var-plug,\n \"chevron-up\": $fa-var-chevron-up,\n \"hand-spock\": $fa-var-hand-spock,\n \"stopwatch\": $fa-var-stopwatch,\n \"face-kiss\": $fa-var-face-kiss,\n \"kiss\": $fa-var-kiss,\n \"bridge-circle-xmark\": $fa-var-bridge-circle-xmark,\n \"face-grin-tongue\": $fa-var-face-grin-tongue,\n \"grin-tongue\": $fa-var-grin-tongue,\n \"chess-bishop\": $fa-var-chess-bishop,\n \"face-grin-wink\": $fa-var-face-grin-wink,\n \"grin-wink\": $fa-var-grin-wink,\n \"ear-deaf\": $fa-var-ear-deaf,\n \"deaf\": $fa-var-deaf,\n \"deafness\": $fa-var-deafness,\n \"hard-of-hearing\": $fa-var-hard-of-hearing,\n \"road-circle-check\": $fa-var-road-circle-check,\n \"dice-five\": $fa-var-dice-five,\n \"square-rss\": $fa-var-square-rss,\n \"rss-square\": $fa-var-rss-square,\n \"land-mine-on\": $fa-var-land-mine-on,\n \"i-cursor\": $fa-var-i-cursor,\n \"stamp\": $fa-var-stamp,\n \"stairs\": $fa-var-stairs,\n \"i\": $fa-var-i,\n \"hryvnia-sign\": $fa-var-hryvnia-sign,\n \"hryvnia\": $fa-var-hryvnia,\n \"pills\": $fa-var-pills,\n \"face-grin-wide\": $fa-var-face-grin-wide,\n \"grin-alt\": $fa-var-grin-alt,\n \"tooth\": $fa-var-tooth,\n \"v\": $fa-var-v,\n \"bangladeshi-taka-sign\": $fa-var-bangladeshi-taka-sign,\n \"bicycle\": $fa-var-bicycle,\n \"staff-snake\": $fa-var-staff-snake,\n \"rod-asclepius\": $fa-var-rod-asclepius,\n \"rod-snake\": $fa-var-rod-snake,\n \"staff-aesculapius\": $fa-var-staff-aesculapius,\n \"head-side-cough-slash\": $fa-var-head-side-cough-slash,\n \"truck-medical\": $fa-var-truck-medical,\n \"ambulance\": $fa-var-ambulance,\n \"wheat-awn-circle-exclamation\": $fa-var-wheat-awn-circle-exclamation,\n \"snowman\": $fa-var-snowman,\n \"mortar-pestle\": $fa-var-mortar-pestle,\n \"road-barrier\": $fa-var-road-barrier,\n \"school\": $fa-var-school,\n \"igloo\": $fa-var-igloo,\n \"joint\": $fa-var-joint,\n \"angle-right\": $fa-var-angle-right,\n \"horse\": $fa-var-horse,\n \"q\": $fa-var-q,\n \"g\": $fa-var-g,\n \"notes-medical\": $fa-var-notes-medical,\n \"temperature-half\": $fa-var-temperature-half,\n \"temperature-2\": $fa-var-temperature-2,\n \"thermometer-2\": $fa-var-thermometer-2,\n \"thermometer-half\": $fa-var-thermometer-half,\n \"dong-sign\": $fa-var-dong-sign,\n \"capsules\": $fa-var-capsules,\n \"poo-storm\": $fa-var-poo-storm,\n \"poo-bolt\": $fa-var-poo-bolt,\n \"face-frown-open\": $fa-var-face-frown-open,\n \"frown-open\": $fa-var-frown-open,\n \"hand-point-up\": $fa-var-hand-point-up,\n \"money-bill\": $fa-var-money-bill,\n \"bookmark\": $fa-var-bookmark,\n \"align-justify\": $fa-var-align-justify,\n \"umbrella-beach\": $fa-var-umbrella-beach,\n \"helmet-un\": $fa-var-helmet-un,\n \"bullseye\": $fa-var-bullseye,\n \"bacon\": $fa-var-bacon,\n \"hand-point-down\": $fa-var-hand-point-down,\n \"arrow-up-from-bracket\": $fa-var-arrow-up-from-bracket,\n \"folder\": $fa-var-folder,\n \"folder-blank\": $fa-var-folder-blank,\n \"file-waveform\": $fa-var-file-waveform,\n \"file-medical-alt\": $fa-var-file-medical-alt,\n \"radiation\": $fa-var-radiation,\n \"chart-simple\": $fa-var-chart-simple,\n \"mars-stroke\": $fa-var-mars-stroke,\n \"vial\": $fa-var-vial,\n \"gauge\": $fa-var-gauge,\n \"dashboard\": $fa-var-dashboard,\n \"gauge-med\": $fa-var-gauge-med,\n \"tachometer-alt-average\": $fa-var-tachometer-alt-average,\n \"wand-magic-sparkles\": $fa-var-wand-magic-sparkles,\n \"magic-wand-sparkles\": $fa-var-magic-wand-sparkles,\n \"e\": $fa-var-e,\n \"pen-clip\": $fa-var-pen-clip,\n \"pen-alt\": $fa-var-pen-alt,\n \"bridge-circle-exclamation\": $fa-var-bridge-circle-exclamation,\n \"user\": $fa-var-user,\n \"school-circle-check\": $fa-var-school-circle-check,\n \"dumpster\": $fa-var-dumpster,\n \"van-shuttle\": $fa-var-van-shuttle,\n \"shuttle-van\": $fa-var-shuttle-van,\n \"building-user\": $fa-var-building-user,\n \"square-caret-left\": $fa-var-square-caret-left,\n \"caret-square-left\": $fa-var-caret-square-left,\n \"highlighter\": $fa-var-highlighter,\n \"key\": $fa-var-key,\n \"bullhorn\": $fa-var-bullhorn,\n \"globe\": $fa-var-globe,\n \"synagogue\": $fa-var-synagogue,\n \"person-half-dress\": $fa-var-person-half-dress,\n \"road-bridge\": $fa-var-road-bridge,\n \"location-arrow\": $fa-var-location-arrow,\n \"c\": $fa-var-c,\n \"tablet-button\": $fa-var-tablet-button,\n \"building-lock\": $fa-var-building-lock,\n \"pizza-slice\": $fa-var-pizza-slice,\n \"money-bill-wave\": $fa-var-money-bill-wave,\n \"chart-area\": $fa-var-chart-area,\n \"area-chart\": $fa-var-area-chart,\n \"house-flag\": $fa-var-house-flag,\n \"person-circle-minus\": $fa-var-person-circle-minus,\n \"ban\": $fa-var-ban,\n \"cancel\": $fa-var-cancel,\n \"camera-rotate\": $fa-var-camera-rotate,\n \"spray-can-sparkles\": $fa-var-spray-can-sparkles,\n \"air-freshener\": $fa-var-air-freshener,\n \"star\": $fa-var-star,\n \"repeat\": $fa-var-repeat,\n \"cross\": $fa-var-cross,\n \"box\": $fa-var-box,\n \"venus-mars\": $fa-var-venus-mars,\n \"arrow-pointer\": $fa-var-arrow-pointer,\n \"mouse-pointer\": $fa-var-mouse-pointer,\n \"maximize\": $fa-var-maximize,\n \"expand-arrows-alt\": $fa-var-expand-arrows-alt,\n \"charging-station\": $fa-var-charging-station,\n \"shapes\": $fa-var-shapes,\n \"triangle-circle-square\": $fa-var-triangle-circle-square,\n \"shuffle\": $fa-var-shuffle,\n \"random\": $fa-var-random,\n \"person-running\": $fa-var-person-running,\n \"running\": $fa-var-running,\n \"mobile-retro\": $fa-var-mobile-retro,\n \"grip-lines-vertical\": $fa-var-grip-lines-vertical,\n \"spider\": $fa-var-spider,\n \"hands-bound\": $fa-var-hands-bound,\n \"file-invoice-dollar\": $fa-var-file-invoice-dollar,\n \"plane-circle-exclamation\": $fa-var-plane-circle-exclamation,\n \"x-ray\": $fa-var-x-ray,\n \"spell-check\": $fa-var-spell-check,\n \"slash\": $fa-var-slash,\n \"computer-mouse\": $fa-var-computer-mouse,\n \"mouse\": $fa-var-mouse,\n \"arrow-right-to-bracket\": $fa-var-arrow-right-to-bracket,\n \"sign-in\": $fa-var-sign-in,\n \"shop-slash\": $fa-var-shop-slash,\n \"store-alt-slash\": $fa-var-store-alt-slash,\n \"server\": $fa-var-server,\n \"virus-covid-slash\": $fa-var-virus-covid-slash,\n \"shop-lock\": $fa-var-shop-lock,\n \"hourglass-start\": $fa-var-hourglass-start,\n \"hourglass-1\": $fa-var-hourglass-1,\n \"blender-phone\": $fa-var-blender-phone,\n \"building-wheat\": $fa-var-building-wheat,\n \"person-breastfeeding\": $fa-var-person-breastfeeding,\n \"right-to-bracket\": $fa-var-right-to-bracket,\n \"sign-in-alt\": $fa-var-sign-in-alt,\n \"venus\": $fa-var-venus,\n \"passport\": $fa-var-passport,\n \"thumbtack-slash\": $fa-var-thumbtack-slash,\n \"thumb-tack-slash\": $fa-var-thumb-tack-slash,\n \"heart-pulse\": $fa-var-heart-pulse,\n \"heartbeat\": $fa-var-heartbeat,\n \"people-carry-box\": $fa-var-people-carry-box,\n \"people-carry\": $fa-var-people-carry,\n \"temperature-high\": $fa-var-temperature-high,\n \"microchip\": $fa-var-microchip,\n \"crown\": $fa-var-crown,\n \"weight-hanging\": $fa-var-weight-hanging,\n \"xmarks-lines\": $fa-var-xmarks-lines,\n \"file-prescription\": $fa-var-file-prescription,\n \"weight-scale\": $fa-var-weight-scale,\n \"weight\": $fa-var-weight,\n \"user-group\": $fa-var-user-group,\n \"user-friends\": $fa-var-user-friends,\n \"arrow-up-a-z\": $fa-var-arrow-up-a-z,\n \"sort-alpha-up\": $fa-var-sort-alpha-up,\n \"chess-knight\": $fa-var-chess-knight,\n \"face-laugh-squint\": $fa-var-face-laugh-squint,\n \"laugh-squint\": $fa-var-laugh-squint,\n \"wheelchair\": $fa-var-wheelchair,\n \"circle-arrow-up\": $fa-var-circle-arrow-up,\n \"arrow-circle-up\": $fa-var-arrow-circle-up,\n \"toggle-on\": $fa-var-toggle-on,\n \"person-walking\": $fa-var-person-walking,\n \"walking\": $fa-var-walking,\n \"l\": $fa-var-l,\n \"fire\": $fa-var-fire,\n \"bed-pulse\": $fa-var-bed-pulse,\n \"procedures\": $fa-var-procedures,\n \"shuttle-space\": $fa-var-shuttle-space,\n \"space-shuttle\": $fa-var-space-shuttle,\n \"face-laugh\": $fa-var-face-laugh,\n \"laugh\": $fa-var-laugh,\n \"folder-open\": $fa-var-folder-open,\n \"heart-circle-plus\": $fa-var-heart-circle-plus,\n \"code-fork\": $fa-var-code-fork,\n \"city\": $fa-var-city,\n \"microphone-lines\": $fa-var-microphone-lines,\n \"microphone-alt\": $fa-var-microphone-alt,\n \"pepper-hot\": $fa-var-pepper-hot,\n \"unlock\": $fa-var-unlock,\n \"colon-sign\": $fa-var-colon-sign,\n \"headset\": $fa-var-headset,\n \"store-slash\": $fa-var-store-slash,\n \"road-circle-xmark\": $fa-var-road-circle-xmark,\n \"user-minus\": $fa-var-user-minus,\n \"mars-stroke-up\": $fa-var-mars-stroke-up,\n \"mars-stroke-v\": $fa-var-mars-stroke-v,\n \"champagne-glasses\": $fa-var-champagne-glasses,\n \"glass-cheers\": $fa-var-glass-cheers,\n \"clipboard\": $fa-var-clipboard,\n \"house-circle-exclamation\": $fa-var-house-circle-exclamation,\n \"file-arrow-up\": $fa-var-file-arrow-up,\n \"file-upload\": $fa-var-file-upload,\n \"wifi\": $fa-var-wifi,\n \"wifi-3\": $fa-var-wifi-3,\n \"wifi-strong\": $fa-var-wifi-strong,\n \"bath\": $fa-var-bath,\n \"bathtub\": $fa-var-bathtub,\n \"underline\": $fa-var-underline,\n \"user-pen\": $fa-var-user-pen,\n \"user-edit\": $fa-var-user-edit,\n \"signature\": $fa-var-signature,\n \"stroopwafel\": $fa-var-stroopwafel,\n \"bold\": $fa-var-bold,\n \"anchor-lock\": $fa-var-anchor-lock,\n \"building-ngo\": $fa-var-building-ngo,\n \"manat-sign\": $fa-var-manat-sign,\n \"not-equal\": $fa-var-not-equal,\n \"border-top-left\": $fa-var-border-top-left,\n \"border-style\": $fa-var-border-style,\n \"map-location-dot\": $fa-var-map-location-dot,\n \"map-marked-alt\": $fa-var-map-marked-alt,\n \"jedi\": $fa-var-jedi,\n \"square-poll-vertical\": $fa-var-square-poll-vertical,\n \"poll\": $fa-var-poll,\n \"mug-hot\": $fa-var-mug-hot,\n \"car-battery\": $fa-var-car-battery,\n \"battery-car\": $fa-var-battery-car,\n \"gift\": $fa-var-gift,\n \"dice-two\": $fa-var-dice-two,\n \"chess-queen\": $fa-var-chess-queen,\n \"glasses\": $fa-var-glasses,\n \"chess-board\": $fa-var-chess-board,\n \"building-circle-check\": $fa-var-building-circle-check,\n \"person-chalkboard\": $fa-var-person-chalkboard,\n \"mars-stroke-right\": $fa-var-mars-stroke-right,\n \"mars-stroke-h\": $fa-var-mars-stroke-h,\n \"hand-back-fist\": $fa-var-hand-back-fist,\n \"hand-rock\": $fa-var-hand-rock,\n \"square-caret-up\": $fa-var-square-caret-up,\n \"caret-square-up\": $fa-var-caret-square-up,\n \"cloud-showers-water\": $fa-var-cloud-showers-water,\n \"chart-bar\": $fa-var-chart-bar,\n \"bar-chart\": $fa-var-bar-chart,\n \"hands-bubbles\": $fa-var-hands-bubbles,\n \"hands-wash\": $fa-var-hands-wash,\n \"less-than-equal\": $fa-var-less-than-equal,\n \"train\": $fa-var-train,\n \"eye-low-vision\": $fa-var-eye-low-vision,\n \"low-vision\": $fa-var-low-vision,\n \"crow\": $fa-var-crow,\n \"sailboat\": $fa-var-sailboat,\n \"window-restore\": $fa-var-window-restore,\n \"square-plus\": $fa-var-square-plus,\n \"plus-square\": $fa-var-plus-square,\n \"torii-gate\": $fa-var-torii-gate,\n \"frog\": $fa-var-frog,\n \"bucket\": $fa-var-bucket,\n \"image\": $fa-var-image,\n \"microphone\": $fa-var-microphone,\n \"cow\": $fa-var-cow,\n \"caret-up\": $fa-var-caret-up,\n \"screwdriver\": $fa-var-screwdriver,\n \"folder-closed\": $fa-var-folder-closed,\n \"house-tsunami\": $fa-var-house-tsunami,\n \"square-nfi\": $fa-var-square-nfi,\n \"arrow-up-from-ground-water\": $fa-var-arrow-up-from-ground-water,\n \"martini-glass\": $fa-var-martini-glass,\n \"glass-martini-alt\": $fa-var-glass-martini-alt,\n \"square-binary\": $fa-var-square-binary,\n \"rotate-left\": $fa-var-rotate-left,\n \"rotate-back\": $fa-var-rotate-back,\n \"rotate-backward\": $fa-var-rotate-backward,\n \"undo-alt\": $fa-var-undo-alt,\n \"table-columns\": $fa-var-table-columns,\n \"columns\": $fa-var-columns,\n \"lemon\": $fa-var-lemon,\n \"head-side-mask\": $fa-var-head-side-mask,\n \"handshake\": $fa-var-handshake,\n \"gem\": $fa-var-gem,\n \"dolly\": $fa-var-dolly,\n \"dolly-box\": $fa-var-dolly-box,\n \"smoking\": $fa-var-smoking,\n \"minimize\": $fa-var-minimize,\n \"compress-arrows-alt\": $fa-var-compress-arrows-alt,\n \"monument\": $fa-var-monument,\n \"snowplow\": $fa-var-snowplow,\n \"angles-right\": $fa-var-angles-right,\n \"angle-double-right\": $fa-var-angle-double-right,\n \"cannabis\": $fa-var-cannabis,\n \"circle-play\": $fa-var-circle-play,\n \"play-circle\": $fa-var-play-circle,\n \"tablets\": $fa-var-tablets,\n \"ethernet\": $fa-var-ethernet,\n \"euro-sign\": $fa-var-euro-sign,\n \"eur\": $fa-var-eur,\n \"euro\": $fa-var-euro,\n \"chair\": $fa-var-chair,\n \"circle-check\": $fa-var-circle-check,\n \"check-circle\": $fa-var-check-circle,\n \"circle-stop\": $fa-var-circle-stop,\n \"stop-circle\": $fa-var-stop-circle,\n \"compass-drafting\": $fa-var-compass-drafting,\n \"drafting-compass\": $fa-var-drafting-compass,\n \"plate-wheat\": $fa-var-plate-wheat,\n \"icicles\": $fa-var-icicles,\n \"person-shelter\": $fa-var-person-shelter,\n \"neuter\": $fa-var-neuter,\n \"id-badge\": $fa-var-id-badge,\n \"marker\": $fa-var-marker,\n \"face-laugh-beam\": $fa-var-face-laugh-beam,\n \"laugh-beam\": $fa-var-laugh-beam,\n \"helicopter-symbol\": $fa-var-helicopter-symbol,\n \"universal-access\": $fa-var-universal-access,\n \"circle-chevron-up\": $fa-var-circle-chevron-up,\n \"chevron-circle-up\": $fa-var-chevron-circle-up,\n \"lari-sign\": $fa-var-lari-sign,\n \"volcano\": $fa-var-volcano,\n \"person-walking-dashed-line-arrow-right\": $fa-var-person-walking-dashed-line-arrow-right,\n \"sterling-sign\": $fa-var-sterling-sign,\n \"gbp\": $fa-var-gbp,\n \"pound-sign\": $fa-var-pound-sign,\n \"viruses\": $fa-var-viruses,\n \"square-person-confined\": $fa-var-square-person-confined,\n \"user-tie\": $fa-var-user-tie,\n \"arrow-down-long\": $fa-var-arrow-down-long,\n \"long-arrow-down\": $fa-var-long-arrow-down,\n \"tent-arrow-down-to-line\": $fa-var-tent-arrow-down-to-line,\n \"certificate\": $fa-var-certificate,\n \"reply-all\": $fa-var-reply-all,\n \"mail-reply-all\": $fa-var-mail-reply-all,\n \"suitcase\": $fa-var-suitcase,\n \"person-skating\": $fa-var-person-skating,\n \"skating\": $fa-var-skating,\n \"filter-circle-dollar\": $fa-var-filter-circle-dollar,\n \"funnel-dollar\": $fa-var-funnel-dollar,\n \"camera-retro\": $fa-var-camera-retro,\n \"circle-arrow-down\": $fa-var-circle-arrow-down,\n \"arrow-circle-down\": $fa-var-arrow-circle-down,\n \"file-import\": $fa-var-file-import,\n \"arrow-right-to-file\": $fa-var-arrow-right-to-file,\n \"square-arrow-up-right\": $fa-var-square-arrow-up-right,\n \"external-link-square\": $fa-var-external-link-square,\n \"box-open\": $fa-var-box-open,\n \"scroll\": $fa-var-scroll,\n \"spa\": $fa-var-spa,\n \"location-pin-lock\": $fa-var-location-pin-lock,\n \"pause\": $fa-var-pause,\n \"hill-avalanche\": $fa-var-hill-avalanche,\n \"temperature-empty\": $fa-var-temperature-empty,\n \"temperature-0\": $fa-var-temperature-0,\n \"thermometer-0\": $fa-var-thermometer-0,\n \"thermometer-empty\": $fa-var-thermometer-empty,\n \"bomb\": $fa-var-bomb,\n \"registered\": $fa-var-registered,\n \"address-card\": $fa-var-address-card,\n \"contact-card\": $fa-var-contact-card,\n \"vcard\": $fa-var-vcard,\n \"scale-unbalanced-flip\": $fa-var-scale-unbalanced-flip,\n \"balance-scale-right\": $fa-var-balance-scale-right,\n \"subscript\": $fa-var-subscript,\n \"diamond-turn-right\": $fa-var-diamond-turn-right,\n \"directions\": $fa-var-directions,\n \"burst\": $fa-var-burst,\n \"house-laptop\": $fa-var-house-laptop,\n \"laptop-house\": $fa-var-laptop-house,\n \"face-tired\": $fa-var-face-tired,\n \"tired\": $fa-var-tired,\n \"money-bills\": $fa-var-money-bills,\n \"smog\": $fa-var-smog,\n \"crutch\": $fa-var-crutch,\n \"cloud-arrow-up\": $fa-var-cloud-arrow-up,\n \"cloud-upload\": $fa-var-cloud-upload,\n \"cloud-upload-alt\": $fa-var-cloud-upload-alt,\n \"palette\": $fa-var-palette,\n \"arrows-turn-right\": $fa-var-arrows-turn-right,\n \"vest\": $fa-var-vest,\n \"ferry\": $fa-var-ferry,\n \"arrows-down-to-people\": $fa-var-arrows-down-to-people,\n \"seedling\": $fa-var-seedling,\n \"sprout\": $fa-var-sprout,\n \"left-right\": $fa-var-left-right,\n \"arrows-alt-h\": $fa-var-arrows-alt-h,\n \"boxes-packing\": $fa-var-boxes-packing,\n \"circle-arrow-left\": $fa-var-circle-arrow-left,\n \"arrow-circle-left\": $fa-var-arrow-circle-left,\n \"group-arrows-rotate\": $fa-var-group-arrows-rotate,\n \"bowl-food\": $fa-var-bowl-food,\n \"candy-cane\": $fa-var-candy-cane,\n \"arrow-down-wide-short\": $fa-var-arrow-down-wide-short,\n \"sort-amount-asc\": $fa-var-sort-amount-asc,\n \"sort-amount-down\": $fa-var-sort-amount-down,\n \"cloud-bolt\": $fa-var-cloud-bolt,\n \"thunderstorm\": $fa-var-thunderstorm,\n \"text-slash\": $fa-var-text-slash,\n \"remove-format\": $fa-var-remove-format,\n \"face-smile-wink\": $fa-var-face-smile-wink,\n \"smile-wink\": $fa-var-smile-wink,\n \"file-word\": $fa-var-file-word,\n \"file-powerpoint\": $fa-var-file-powerpoint,\n \"arrows-left-right\": $fa-var-arrows-left-right,\n \"arrows-h\": $fa-var-arrows-h,\n \"house-lock\": $fa-var-house-lock,\n \"cloud-arrow-down\": $fa-var-cloud-arrow-down,\n \"cloud-download\": $fa-var-cloud-download,\n \"cloud-download-alt\": $fa-var-cloud-download-alt,\n \"children\": $fa-var-children,\n \"chalkboard\": $fa-var-chalkboard,\n \"blackboard\": $fa-var-blackboard,\n \"user-large-slash\": $fa-var-user-large-slash,\n \"user-alt-slash\": $fa-var-user-alt-slash,\n \"envelope-open\": $fa-var-envelope-open,\n \"handshake-simple-slash\": $fa-var-handshake-simple-slash,\n \"handshake-alt-slash\": $fa-var-handshake-alt-slash,\n \"mattress-pillow\": $fa-var-mattress-pillow,\n \"guarani-sign\": $fa-var-guarani-sign,\n \"arrows-rotate\": $fa-var-arrows-rotate,\n \"refresh\": $fa-var-refresh,\n \"sync\": $fa-var-sync,\n \"fire-extinguisher\": $fa-var-fire-extinguisher,\n \"cruzeiro-sign\": $fa-var-cruzeiro-sign,\n \"greater-than-equal\": $fa-var-greater-than-equal,\n \"shield-halved\": $fa-var-shield-halved,\n \"shield-alt\": $fa-var-shield-alt,\n \"book-atlas\": $fa-var-book-atlas,\n \"atlas\": $fa-var-atlas,\n \"virus\": $fa-var-virus,\n \"envelope-circle-check\": $fa-var-envelope-circle-check,\n \"layer-group\": $fa-var-layer-group,\n \"arrows-to-dot\": $fa-var-arrows-to-dot,\n \"archway\": $fa-var-archway,\n \"heart-circle-check\": $fa-var-heart-circle-check,\n \"house-chimney-crack\": $fa-var-house-chimney-crack,\n \"house-damage\": $fa-var-house-damage,\n \"file-zipper\": $fa-var-file-zipper,\n \"file-archive\": $fa-var-file-archive,\n \"square\": $fa-var-square,\n \"martini-glass-empty\": $fa-var-martini-glass-empty,\n \"glass-martini\": $fa-var-glass-martini,\n \"couch\": $fa-var-couch,\n \"cedi-sign\": $fa-var-cedi-sign,\n \"italic\": $fa-var-italic,\n \"table-cells-column-lock\": $fa-var-table-cells-column-lock,\n \"church\": $fa-var-church,\n \"comments-dollar\": $fa-var-comments-dollar,\n \"democrat\": $fa-var-democrat,\n \"z\": $fa-var-z,\n \"person-skiing\": $fa-var-person-skiing,\n \"skiing\": $fa-var-skiing,\n \"road-lock\": $fa-var-road-lock,\n \"a\": $fa-var-a,\n \"temperature-arrow-down\": $fa-var-temperature-arrow-down,\n \"temperature-down\": $fa-var-temperature-down,\n \"feather-pointed\": $fa-var-feather-pointed,\n \"feather-alt\": $fa-var-feather-alt,\n \"p\": $fa-var-p,\n \"snowflake\": $fa-var-snowflake,\n \"newspaper\": $fa-var-newspaper,\n \"rectangle-ad\": $fa-var-rectangle-ad,\n \"ad\": $fa-var-ad,\n \"circle-arrow-right\": $fa-var-circle-arrow-right,\n \"arrow-circle-right\": $fa-var-arrow-circle-right,\n \"filter-circle-xmark\": $fa-var-filter-circle-xmark,\n \"locust\": $fa-var-locust,\n \"sort\": $fa-var-sort,\n \"unsorted\": $fa-var-unsorted,\n \"list-ol\": $fa-var-list-ol,\n \"list-1-2\": $fa-var-list-1-2,\n \"list-numeric\": $fa-var-list-numeric,\n \"person-dress-burst\": $fa-var-person-dress-burst,\n \"money-check-dollar\": $fa-var-money-check-dollar,\n \"money-check-alt\": $fa-var-money-check-alt,\n \"vector-square\": $fa-var-vector-square,\n \"bread-slice\": $fa-var-bread-slice,\n \"language\": $fa-var-language,\n \"face-kiss-wink-heart\": $fa-var-face-kiss-wink-heart,\n \"kiss-wink-heart\": $fa-var-kiss-wink-heart,\n \"filter\": $fa-var-filter,\n \"question\": $fa-var-question,\n \"file-signature\": $fa-var-file-signature,\n \"up-down-left-right\": $fa-var-up-down-left-right,\n \"arrows-alt\": $fa-var-arrows-alt,\n \"house-chimney-user\": $fa-var-house-chimney-user,\n \"hand-holding-heart\": $fa-var-hand-holding-heart,\n \"puzzle-piece\": $fa-var-puzzle-piece,\n \"money-check\": $fa-var-money-check,\n \"star-half-stroke\": $fa-var-star-half-stroke,\n \"star-half-alt\": $fa-var-star-half-alt,\n \"code\": $fa-var-code,\n \"whiskey-glass\": $fa-var-whiskey-glass,\n \"glass-whiskey\": $fa-var-glass-whiskey,\n \"building-circle-exclamation\": $fa-var-building-circle-exclamation,\n \"magnifying-glass-chart\": $fa-var-magnifying-glass-chart,\n \"arrow-up-right-from-square\": $fa-var-arrow-up-right-from-square,\n \"external-link\": $fa-var-external-link,\n \"cubes-stacked\": $fa-var-cubes-stacked,\n \"won-sign\": $fa-var-won-sign,\n \"krw\": $fa-var-krw,\n \"won\": $fa-var-won,\n \"virus-covid\": $fa-var-virus-covid,\n \"austral-sign\": $fa-var-austral-sign,\n \"f\": $fa-var-f,\n \"leaf\": $fa-var-leaf,\n \"road\": $fa-var-road,\n \"taxi\": $fa-var-taxi,\n \"cab\": $fa-var-cab,\n \"person-circle-plus\": $fa-var-person-circle-plus,\n \"chart-pie\": $fa-var-chart-pie,\n \"pie-chart\": $fa-var-pie-chart,\n \"bolt-lightning\": $fa-var-bolt-lightning,\n \"sack-xmark\": $fa-var-sack-xmark,\n \"file-excel\": $fa-var-file-excel,\n \"file-contract\": $fa-var-file-contract,\n \"fish-fins\": $fa-var-fish-fins,\n \"building-flag\": $fa-var-building-flag,\n \"face-grin-beam\": $fa-var-face-grin-beam,\n \"grin-beam\": $fa-var-grin-beam,\n \"object-ungroup\": $fa-var-object-ungroup,\n \"poop\": $fa-var-poop,\n \"location-pin\": $fa-var-location-pin,\n \"map-marker\": $fa-var-map-marker,\n \"kaaba\": $fa-var-kaaba,\n \"toilet-paper\": $fa-var-toilet-paper,\n \"helmet-safety\": $fa-var-helmet-safety,\n \"hard-hat\": $fa-var-hard-hat,\n \"hat-hard\": $fa-var-hat-hard,\n \"eject\": $fa-var-eject,\n \"circle-right\": $fa-var-circle-right,\n \"arrow-alt-circle-right\": $fa-var-arrow-alt-circle-right,\n \"plane-circle-check\": $fa-var-plane-circle-check,\n \"face-rolling-eyes\": $fa-var-face-rolling-eyes,\n \"meh-rolling-eyes\": $fa-var-meh-rolling-eyes,\n \"object-group\": $fa-var-object-group,\n \"chart-line\": $fa-var-chart-line,\n \"line-chart\": $fa-var-line-chart,\n \"mask-ventilator\": $fa-var-mask-ventilator,\n \"arrow-right\": $fa-var-arrow-right,\n \"signs-post\": $fa-var-signs-post,\n \"map-signs\": $fa-var-map-signs,\n \"cash-register\": $fa-var-cash-register,\n \"person-circle-question\": $fa-var-person-circle-question,\n \"h\": $fa-var-h,\n \"tarp\": $fa-var-tarp,\n \"screwdriver-wrench\": $fa-var-screwdriver-wrench,\n \"tools\": $fa-var-tools,\n \"arrows-to-eye\": $fa-var-arrows-to-eye,\n \"plug-circle-bolt\": $fa-var-plug-circle-bolt,\n \"heart\": $fa-var-heart,\n \"mars-and-venus\": $fa-var-mars-and-venus,\n \"house-user\": $fa-var-house-user,\n \"home-user\": $fa-var-home-user,\n \"dumpster-fire\": $fa-var-dumpster-fire,\n \"house-crack\": $fa-var-house-crack,\n \"martini-glass-citrus\": $fa-var-martini-glass-citrus,\n \"cocktail\": $fa-var-cocktail,\n \"face-surprise\": $fa-var-face-surprise,\n \"surprise\": $fa-var-surprise,\n \"bottle-water\": $fa-var-bottle-water,\n \"circle-pause\": $fa-var-circle-pause,\n \"pause-circle\": $fa-var-pause-circle,\n \"toilet-paper-slash\": $fa-var-toilet-paper-slash,\n \"apple-whole\": $fa-var-apple-whole,\n \"apple-alt\": $fa-var-apple-alt,\n \"kitchen-set\": $fa-var-kitchen-set,\n \"r\": $fa-var-r,\n \"temperature-quarter\": $fa-var-temperature-quarter,\n \"temperature-1\": $fa-var-temperature-1,\n \"thermometer-1\": $fa-var-thermometer-1,\n \"thermometer-quarter\": $fa-var-thermometer-quarter,\n \"cube\": $fa-var-cube,\n \"bitcoin-sign\": $fa-var-bitcoin-sign,\n \"shield-dog\": $fa-var-shield-dog,\n \"solar-panel\": $fa-var-solar-panel,\n \"lock-open\": $fa-var-lock-open,\n \"elevator\": $fa-var-elevator,\n \"money-bill-transfer\": $fa-var-money-bill-transfer,\n \"money-bill-trend-up\": $fa-var-money-bill-trend-up,\n \"house-flood-water-circle-arrow-right\": $fa-var-house-flood-water-circle-arrow-right,\n \"square-poll-horizontal\": $fa-var-square-poll-horizontal,\n \"poll-h\": $fa-var-poll-h,\n \"circle\": $fa-var-circle,\n \"backward-fast\": $fa-var-backward-fast,\n \"fast-backward\": $fa-var-fast-backward,\n \"recycle\": $fa-var-recycle,\n \"user-astronaut\": $fa-var-user-astronaut,\n \"plane-slash\": $fa-var-plane-slash,\n \"trademark\": $fa-var-trademark,\n \"basketball\": $fa-var-basketball,\n \"basketball-ball\": $fa-var-basketball-ball,\n \"satellite-dish\": $fa-var-satellite-dish,\n \"circle-up\": $fa-var-circle-up,\n \"arrow-alt-circle-up\": $fa-var-arrow-alt-circle-up,\n \"mobile-screen-button\": $fa-var-mobile-screen-button,\n \"mobile-alt\": $fa-var-mobile-alt,\n \"volume-high\": $fa-var-volume-high,\n \"volume-up\": $fa-var-volume-up,\n \"users-rays\": $fa-var-users-rays,\n \"wallet\": $fa-var-wallet,\n \"clipboard-check\": $fa-var-clipboard-check,\n \"file-audio\": $fa-var-file-audio,\n \"burger\": $fa-var-burger,\n \"hamburger\": $fa-var-hamburger,\n \"wrench\": $fa-var-wrench,\n \"bugs\": $fa-var-bugs,\n \"rupee-sign\": $fa-var-rupee-sign,\n \"rupee\": $fa-var-rupee,\n \"file-image\": $fa-var-file-image,\n \"circle-question\": $fa-var-circle-question,\n \"question-circle\": $fa-var-question-circle,\n \"plane-departure\": $fa-var-plane-departure,\n \"handshake-slash\": $fa-var-handshake-slash,\n \"book-bookmark\": $fa-var-book-bookmark,\n \"code-branch\": $fa-var-code-branch,\n \"hat-cowboy\": $fa-var-hat-cowboy,\n \"bridge\": $fa-var-bridge,\n \"phone-flip\": $fa-var-phone-flip,\n \"phone-alt\": $fa-var-phone-alt,\n \"truck-front\": $fa-var-truck-front,\n \"cat\": $fa-var-cat,\n \"anchor-circle-exclamation\": $fa-var-anchor-circle-exclamation,\n \"truck-field\": $fa-var-truck-field,\n \"route\": $fa-var-route,\n \"clipboard-question\": $fa-var-clipboard-question,\n \"panorama\": $fa-var-panorama,\n \"comment-medical\": $fa-var-comment-medical,\n \"teeth-open\": $fa-var-teeth-open,\n \"file-circle-minus\": $fa-var-file-circle-minus,\n \"tags\": $fa-var-tags,\n \"wine-glass\": $fa-var-wine-glass,\n \"forward-fast\": $fa-var-forward-fast,\n \"fast-forward\": $fa-var-fast-forward,\n \"face-meh-blank\": $fa-var-face-meh-blank,\n \"meh-blank\": $fa-var-meh-blank,\n \"square-parking\": $fa-var-square-parking,\n \"parking\": $fa-var-parking,\n \"house-signal\": $fa-var-house-signal,\n \"bars-progress\": $fa-var-bars-progress,\n \"tasks-alt\": $fa-var-tasks-alt,\n \"faucet-drip\": $fa-var-faucet-drip,\n \"cart-flatbed\": $fa-var-cart-flatbed,\n \"dolly-flatbed\": $fa-var-dolly-flatbed,\n \"ban-smoking\": $fa-var-ban-smoking,\n \"smoking-ban\": $fa-var-smoking-ban,\n \"terminal\": $fa-var-terminal,\n \"mobile-button\": $fa-var-mobile-button,\n \"house-medical-flag\": $fa-var-house-medical-flag,\n \"basket-shopping\": $fa-var-basket-shopping,\n \"shopping-basket\": $fa-var-shopping-basket,\n \"tape\": $fa-var-tape,\n \"bus-simple\": $fa-var-bus-simple,\n \"bus-alt\": $fa-var-bus-alt,\n \"eye\": $fa-var-eye,\n \"face-sad-cry\": $fa-var-face-sad-cry,\n \"sad-cry\": $fa-var-sad-cry,\n \"audio-description\": $fa-var-audio-description,\n \"person-military-to-person\": $fa-var-person-military-to-person,\n \"file-shield\": $fa-var-file-shield,\n \"user-slash\": $fa-var-user-slash,\n \"pen\": $fa-var-pen,\n \"tower-observation\": $fa-var-tower-observation,\n \"file-code\": $fa-var-file-code,\n \"signal\": $fa-var-signal,\n \"signal-5\": $fa-var-signal-5,\n \"signal-perfect\": $fa-var-signal-perfect,\n \"bus\": $fa-var-bus,\n \"heart-circle-xmark\": $fa-var-heart-circle-xmark,\n \"house-chimney\": $fa-var-house-chimney,\n \"home-lg\": $fa-var-home-lg,\n \"window-maximize\": $fa-var-window-maximize,\n \"face-frown\": $fa-var-face-frown,\n \"frown\": $fa-var-frown,\n \"prescription\": $fa-var-prescription,\n \"shop\": $fa-var-shop,\n \"store-alt\": $fa-var-store-alt,\n \"floppy-disk\": $fa-var-floppy-disk,\n \"save\": $fa-var-save,\n \"vihara\": $fa-var-vihara,\n \"scale-unbalanced\": $fa-var-scale-unbalanced,\n \"balance-scale-left\": $fa-var-balance-scale-left,\n \"sort-up\": $fa-var-sort-up,\n \"sort-asc\": $fa-var-sort-asc,\n \"comment-dots\": $fa-var-comment-dots,\n \"commenting\": $fa-var-commenting,\n \"plant-wilt\": $fa-var-plant-wilt,\n \"diamond\": $fa-var-diamond,\n \"face-grin-squint\": $fa-var-face-grin-squint,\n \"grin-squint\": $fa-var-grin-squint,\n \"hand-holding-dollar\": $fa-var-hand-holding-dollar,\n \"hand-holding-usd\": $fa-var-hand-holding-usd,\n \"chart-diagram\": $fa-var-chart-diagram,\n \"bacterium\": $fa-var-bacterium,\n \"hand-pointer\": $fa-var-hand-pointer,\n \"drum-steelpan\": $fa-var-drum-steelpan,\n \"hand-scissors\": $fa-var-hand-scissors,\n \"hands-praying\": $fa-var-hands-praying,\n \"praying-hands\": $fa-var-praying-hands,\n \"arrow-rotate-right\": $fa-var-arrow-rotate-right,\n \"arrow-right-rotate\": $fa-var-arrow-right-rotate,\n \"arrow-rotate-forward\": $fa-var-arrow-rotate-forward,\n \"redo\": $fa-var-redo,\n \"biohazard\": $fa-var-biohazard,\n \"location-crosshairs\": $fa-var-location-crosshairs,\n \"location\": $fa-var-location,\n \"mars-double\": $fa-var-mars-double,\n \"child-dress\": $fa-var-child-dress,\n \"users-between-lines\": $fa-var-users-between-lines,\n \"lungs-virus\": $fa-var-lungs-virus,\n \"face-grin-tears\": $fa-var-face-grin-tears,\n \"grin-tears\": $fa-var-grin-tears,\n \"phone\": $fa-var-phone,\n \"calendar-xmark\": $fa-var-calendar-xmark,\n \"calendar-times\": $fa-var-calendar-times,\n \"child-reaching\": $fa-var-child-reaching,\n \"head-side-virus\": $fa-var-head-side-virus,\n \"user-gear\": $fa-var-user-gear,\n \"user-cog\": $fa-var-user-cog,\n \"arrow-up-1-9\": $fa-var-arrow-up-1-9,\n \"sort-numeric-up\": $fa-var-sort-numeric-up,\n \"door-closed\": $fa-var-door-closed,\n \"shield-virus\": $fa-var-shield-virus,\n \"dice-six\": $fa-var-dice-six,\n \"mosquito-net\": $fa-var-mosquito-net,\n \"file-fragment\": $fa-var-file-fragment,\n \"bridge-water\": $fa-var-bridge-water,\n \"person-booth\": $fa-var-person-booth,\n \"text-width\": $fa-var-text-width,\n \"hat-wizard\": $fa-var-hat-wizard,\n \"pen-fancy\": $fa-var-pen-fancy,\n \"person-digging\": $fa-var-person-digging,\n \"digging\": $fa-var-digging,\n \"trash\": $fa-var-trash,\n \"gauge-simple\": $fa-var-gauge-simple,\n \"gauge-simple-med\": $fa-var-gauge-simple-med,\n \"tachometer-average\": $fa-var-tachometer-average,\n \"book-medical\": $fa-var-book-medical,\n \"poo\": $fa-var-poo,\n \"quote-right\": $fa-var-quote-right,\n \"quote-right-alt\": $fa-var-quote-right-alt,\n \"shirt\": $fa-var-shirt,\n \"t-shirt\": $fa-var-t-shirt,\n \"tshirt\": $fa-var-tshirt,\n \"cubes\": $fa-var-cubes,\n \"divide\": $fa-var-divide,\n \"tenge-sign\": $fa-var-tenge-sign,\n \"tenge\": $fa-var-tenge,\n \"headphones\": $fa-var-headphones,\n \"hands-holding\": $fa-var-hands-holding,\n \"hands-clapping\": $fa-var-hands-clapping,\n \"republican\": $fa-var-republican,\n \"arrow-left\": $fa-var-arrow-left,\n \"person-circle-xmark\": $fa-var-person-circle-xmark,\n \"ruler\": $fa-var-ruler,\n \"align-left\": $fa-var-align-left,\n \"dice-d6\": $fa-var-dice-d6,\n \"restroom\": $fa-var-restroom,\n \"j\": $fa-var-j,\n \"users-viewfinder\": $fa-var-users-viewfinder,\n \"file-video\": $fa-var-file-video,\n \"up-right-from-square\": $fa-var-up-right-from-square,\n \"external-link-alt\": $fa-var-external-link-alt,\n \"table-cells\": $fa-var-table-cells,\n \"th\": $fa-var-th,\n \"file-pdf\": $fa-var-file-pdf,\n \"book-bible\": $fa-var-book-bible,\n \"bible\": $fa-var-bible,\n \"o\": $fa-var-o,\n \"suitcase-medical\": $fa-var-suitcase-medical,\n \"medkit\": $fa-var-medkit,\n \"user-secret\": $fa-var-user-secret,\n \"otter\": $fa-var-otter,\n \"person-dress\": $fa-var-person-dress,\n \"female\": $fa-var-female,\n \"comment-dollar\": $fa-var-comment-dollar,\n \"business-time\": $fa-var-business-time,\n \"briefcase-clock\": $fa-var-briefcase-clock,\n \"table-cells-large\": $fa-var-table-cells-large,\n \"th-large\": $fa-var-th-large,\n \"book-tanakh\": $fa-var-book-tanakh,\n \"tanakh\": $fa-var-tanakh,\n \"phone-volume\": $fa-var-phone-volume,\n \"volume-control-phone\": $fa-var-volume-control-phone,\n \"hat-cowboy-side\": $fa-var-hat-cowboy-side,\n \"clipboard-user\": $fa-var-clipboard-user,\n \"child\": $fa-var-child,\n \"lira-sign\": $fa-var-lira-sign,\n \"satellite\": $fa-var-satellite,\n \"plane-lock\": $fa-var-plane-lock,\n \"tag\": $fa-var-tag,\n \"comment\": $fa-var-comment,\n \"cake-candles\": $fa-var-cake-candles,\n \"birthday-cake\": $fa-var-birthday-cake,\n \"cake\": $fa-var-cake,\n \"envelope\": $fa-var-envelope,\n \"angles-up\": $fa-var-angles-up,\n \"angle-double-up\": $fa-var-angle-double-up,\n \"paperclip\": $fa-var-paperclip,\n \"arrow-right-to-city\": $fa-var-arrow-right-to-city,\n \"ribbon\": $fa-var-ribbon,\n \"lungs\": $fa-var-lungs,\n \"arrow-up-9-1\": $fa-var-arrow-up-9-1,\n \"sort-numeric-up-alt\": $fa-var-sort-numeric-up-alt,\n \"litecoin-sign\": $fa-var-litecoin-sign,\n \"border-none\": $fa-var-border-none,\n \"circle-nodes\": $fa-var-circle-nodes,\n \"parachute-box\": $fa-var-parachute-box,\n \"indent\": $fa-var-indent,\n \"truck-field-un\": $fa-var-truck-field-un,\n \"hourglass\": $fa-var-hourglass,\n \"hourglass-empty\": $fa-var-hourglass-empty,\n \"mountain\": $fa-var-mountain,\n \"user-doctor\": $fa-var-user-doctor,\n \"user-md\": $fa-var-user-md,\n \"circle-info\": $fa-var-circle-info,\n \"info-circle\": $fa-var-info-circle,\n \"cloud-meatball\": $fa-var-cloud-meatball,\n \"camera\": $fa-var-camera,\n \"camera-alt\": $fa-var-camera-alt,\n \"square-virus\": $fa-var-square-virus,\n \"meteor\": $fa-var-meteor,\n \"car-on\": $fa-var-car-on,\n \"sleigh\": $fa-var-sleigh,\n \"arrow-down-1-9\": $fa-var-arrow-down-1-9,\n \"sort-numeric-asc\": $fa-var-sort-numeric-asc,\n \"sort-numeric-down\": $fa-var-sort-numeric-down,\n \"hand-holding-droplet\": $fa-var-hand-holding-droplet,\n \"hand-holding-water\": $fa-var-hand-holding-water,\n \"water\": $fa-var-water,\n \"calendar-check\": $fa-var-calendar-check,\n \"braille\": $fa-var-braille,\n \"prescription-bottle-medical\": $fa-var-prescription-bottle-medical,\n \"prescription-bottle-alt\": $fa-var-prescription-bottle-alt,\n \"landmark\": $fa-var-landmark,\n \"truck\": $fa-var-truck,\n \"crosshairs\": $fa-var-crosshairs,\n \"person-cane\": $fa-var-person-cane,\n \"tent\": $fa-var-tent,\n \"vest-patches\": $fa-var-vest-patches,\n \"check-double\": $fa-var-check-double,\n \"arrow-down-a-z\": $fa-var-arrow-down-a-z,\n \"sort-alpha-asc\": $fa-var-sort-alpha-asc,\n \"sort-alpha-down\": $fa-var-sort-alpha-down,\n \"money-bill-wheat\": $fa-var-money-bill-wheat,\n \"cookie\": $fa-var-cookie,\n \"arrow-rotate-left\": $fa-var-arrow-rotate-left,\n \"arrow-left-rotate\": $fa-var-arrow-left-rotate,\n \"arrow-rotate-back\": $fa-var-arrow-rotate-back,\n \"arrow-rotate-backward\": $fa-var-arrow-rotate-backward,\n \"undo\": $fa-var-undo,\n \"hard-drive\": $fa-var-hard-drive,\n \"hdd\": $fa-var-hdd,\n \"face-grin-squint-tears\": $fa-var-face-grin-squint-tears,\n \"grin-squint-tears\": $fa-var-grin-squint-tears,\n \"dumbbell\": $fa-var-dumbbell,\n \"rectangle-list\": $fa-var-rectangle-list,\n \"list-alt\": $fa-var-list-alt,\n \"tarp-droplet\": $fa-var-tarp-droplet,\n \"house-medical-circle-check\": $fa-var-house-medical-circle-check,\n \"person-skiing-nordic\": $fa-var-person-skiing-nordic,\n \"skiing-nordic\": $fa-var-skiing-nordic,\n \"calendar-plus\": $fa-var-calendar-plus,\n \"plane-arrival\": $fa-var-plane-arrival,\n \"circle-left\": $fa-var-circle-left,\n \"arrow-alt-circle-left\": $fa-var-arrow-alt-circle-left,\n \"train-subway\": $fa-var-train-subway,\n \"subway\": $fa-var-subway,\n \"chart-gantt\": $fa-var-chart-gantt,\n \"indian-rupee-sign\": $fa-var-indian-rupee-sign,\n \"indian-rupee\": $fa-var-indian-rupee,\n \"inr\": $fa-var-inr,\n \"crop-simple\": $fa-var-crop-simple,\n \"crop-alt\": $fa-var-crop-alt,\n \"money-bill-1\": $fa-var-money-bill-1,\n \"money-bill-alt\": $fa-var-money-bill-alt,\n \"left-long\": $fa-var-left-long,\n \"long-arrow-alt-left\": $fa-var-long-arrow-alt-left,\n \"dna\": $fa-var-dna,\n \"virus-slash\": $fa-var-virus-slash,\n \"minus\": $fa-var-minus,\n \"subtract\": $fa-var-subtract,\n \"chess\": $fa-var-chess,\n \"arrow-left-long\": $fa-var-arrow-left-long,\n \"long-arrow-left\": $fa-var-long-arrow-left,\n \"plug-circle-check\": $fa-var-plug-circle-check,\n \"street-view\": $fa-var-street-view,\n \"franc-sign\": $fa-var-franc-sign,\n \"volume-off\": $fa-var-volume-off,\n \"hands-asl-interpreting\": $fa-var-hands-asl-interpreting,\n \"american-sign-language-interpreting\": $fa-var-american-sign-language-interpreting,\n \"asl-interpreting\": $fa-var-asl-interpreting,\n \"hands-american-sign-language-interpreting\": $fa-var-hands-american-sign-language-interpreting,\n \"gear\": $fa-var-gear,\n \"cog\": $fa-var-cog,\n \"droplet-slash\": $fa-var-droplet-slash,\n \"tint-slash\": $fa-var-tint-slash,\n \"mosque\": $fa-var-mosque,\n \"mosquito\": $fa-var-mosquito,\n \"star-of-david\": $fa-var-star-of-david,\n \"person-military-rifle\": $fa-var-person-military-rifle,\n \"cart-shopping\": $fa-var-cart-shopping,\n \"shopping-cart\": $fa-var-shopping-cart,\n \"vials\": $fa-var-vials,\n \"plug-circle-plus\": $fa-var-plug-circle-plus,\n \"place-of-worship\": $fa-var-place-of-worship,\n \"grip-vertical\": $fa-var-grip-vertical,\n \"hexagon-nodes\": $fa-var-hexagon-nodes,\n \"arrow-turn-up\": $fa-var-arrow-turn-up,\n \"level-up\": $fa-var-level-up,\n \"u\": $fa-var-u,\n \"square-root-variable\": $fa-var-square-root-variable,\n \"square-root-alt\": $fa-var-square-root-alt,\n \"clock\": $fa-var-clock,\n \"clock-four\": $fa-var-clock-four,\n \"backward-step\": $fa-var-backward-step,\n \"step-backward\": $fa-var-step-backward,\n \"pallet\": $fa-var-pallet,\n \"faucet\": $fa-var-faucet,\n \"baseball-bat-ball\": $fa-var-baseball-bat-ball,\n \"s\": $fa-var-s,\n \"timeline\": $fa-var-timeline,\n \"keyboard\": $fa-var-keyboard,\n \"caret-down\": $fa-var-caret-down,\n \"house-chimney-medical\": $fa-var-house-chimney-medical,\n \"clinic-medical\": $fa-var-clinic-medical,\n \"temperature-three-quarters\": $fa-var-temperature-three-quarters,\n \"temperature-3\": $fa-var-temperature-3,\n \"thermometer-3\": $fa-var-thermometer-3,\n \"thermometer-three-quarters\": $fa-var-thermometer-three-quarters,\n \"mobile-screen\": $fa-var-mobile-screen,\n \"mobile-android-alt\": $fa-var-mobile-android-alt,\n \"plane-up\": $fa-var-plane-up,\n \"piggy-bank\": $fa-var-piggy-bank,\n \"battery-half\": $fa-var-battery-half,\n \"battery-3\": $fa-var-battery-3,\n \"mountain-city\": $fa-var-mountain-city,\n \"coins\": $fa-var-coins,\n \"khanda\": $fa-var-khanda,\n \"sliders\": $fa-var-sliders,\n \"sliders-h\": $fa-var-sliders-h,\n \"folder-tree\": $fa-var-folder-tree,\n \"network-wired\": $fa-var-network-wired,\n \"map-pin\": $fa-var-map-pin,\n \"hamsa\": $fa-var-hamsa,\n \"cent-sign\": $fa-var-cent-sign,\n \"flask\": $fa-var-flask,\n \"person-pregnant\": $fa-var-person-pregnant,\n \"wand-sparkles\": $fa-var-wand-sparkles,\n \"ellipsis-vertical\": $fa-var-ellipsis-vertical,\n \"ellipsis-v\": $fa-var-ellipsis-v,\n \"ticket\": $fa-var-ticket,\n \"power-off\": $fa-var-power-off,\n \"right-long\": $fa-var-right-long,\n \"long-arrow-alt-right\": $fa-var-long-arrow-alt-right,\n \"flag-usa\": $fa-var-flag-usa,\n \"laptop-file\": $fa-var-laptop-file,\n \"tty\": $fa-var-tty,\n \"teletype\": $fa-var-teletype,\n \"diagram-next\": $fa-var-diagram-next,\n \"person-rifle\": $fa-var-person-rifle,\n \"house-medical-circle-exclamation\": $fa-var-house-medical-circle-exclamation,\n \"closed-captioning\": $fa-var-closed-captioning,\n \"person-hiking\": $fa-var-person-hiking,\n \"hiking\": $fa-var-hiking,\n \"venus-double\": $fa-var-venus-double,\n \"images\": $fa-var-images,\n \"calculator\": $fa-var-calculator,\n \"people-pulling\": $fa-var-people-pulling,\n \"n\": $fa-var-n,\n \"cable-car\": $fa-var-cable-car,\n \"tram\": $fa-var-tram,\n \"cloud-rain\": $fa-var-cloud-rain,\n \"building-circle-xmark\": $fa-var-building-circle-xmark,\n \"ship\": $fa-var-ship,\n \"arrows-down-to-line\": $fa-var-arrows-down-to-line,\n \"download\": $fa-var-download,\n \"face-grin\": $fa-var-face-grin,\n \"grin\": $fa-var-grin,\n \"delete-left\": $fa-var-delete-left,\n \"backspace\": $fa-var-backspace,\n \"eye-dropper\": $fa-var-eye-dropper,\n \"eye-dropper-empty\": $fa-var-eye-dropper-empty,\n \"eyedropper\": $fa-var-eyedropper,\n \"file-circle-check\": $fa-var-file-circle-check,\n \"forward\": $fa-var-forward,\n \"mobile\": $fa-var-mobile,\n \"mobile-android\": $fa-var-mobile-android,\n \"mobile-phone\": $fa-var-mobile-phone,\n \"face-meh\": $fa-var-face-meh,\n \"meh\": $fa-var-meh,\n \"align-center\": $fa-var-align-center,\n \"book-skull\": $fa-var-book-skull,\n \"book-dead\": $fa-var-book-dead,\n \"id-card\": $fa-var-id-card,\n \"drivers-license\": $fa-var-drivers-license,\n \"outdent\": $fa-var-outdent,\n \"dedent\": $fa-var-dedent,\n \"heart-circle-exclamation\": $fa-var-heart-circle-exclamation,\n \"house\": $fa-var-house,\n \"home\": $fa-var-home,\n \"home-alt\": $fa-var-home-alt,\n \"home-lg-alt\": $fa-var-home-lg-alt,\n \"calendar-week\": $fa-var-calendar-week,\n \"laptop-medical\": $fa-var-laptop-medical,\n \"b\": $fa-var-b,\n \"file-medical\": $fa-var-file-medical,\n \"dice-one\": $fa-var-dice-one,\n \"kiwi-bird\": $fa-var-kiwi-bird,\n \"arrow-right-arrow-left\": $fa-var-arrow-right-arrow-left,\n \"exchange\": $fa-var-exchange,\n \"rotate-right\": $fa-var-rotate-right,\n \"redo-alt\": $fa-var-redo-alt,\n \"rotate-forward\": $fa-var-rotate-forward,\n \"utensils\": $fa-var-utensils,\n \"cutlery\": $fa-var-cutlery,\n \"arrow-up-wide-short\": $fa-var-arrow-up-wide-short,\n \"sort-amount-up\": $fa-var-sort-amount-up,\n \"mill-sign\": $fa-var-mill-sign,\n \"bowl-rice\": $fa-var-bowl-rice,\n \"skull\": $fa-var-skull,\n \"tower-broadcast\": $fa-var-tower-broadcast,\n \"broadcast-tower\": $fa-var-broadcast-tower,\n \"truck-pickup\": $fa-var-truck-pickup,\n \"up-long\": $fa-var-up-long,\n \"long-arrow-alt-up\": $fa-var-long-arrow-alt-up,\n \"stop\": $fa-var-stop,\n \"code-merge\": $fa-var-code-merge,\n \"upload\": $fa-var-upload,\n \"hurricane\": $fa-var-hurricane,\n \"mound\": $fa-var-mound,\n \"toilet-portable\": $fa-var-toilet-portable,\n \"compact-disc\": $fa-var-compact-disc,\n \"file-arrow-down\": $fa-var-file-arrow-down,\n \"file-download\": $fa-var-file-download,\n \"caravan\": $fa-var-caravan,\n \"shield-cat\": $fa-var-shield-cat,\n \"bolt\": $fa-var-bolt,\n \"zap\": $fa-var-zap,\n \"glass-water\": $fa-var-glass-water,\n \"oil-well\": $fa-var-oil-well,\n \"vault\": $fa-var-vault,\n \"mars\": $fa-var-mars,\n \"toilet\": $fa-var-toilet,\n \"plane-circle-xmark\": $fa-var-plane-circle-xmark,\n \"yen-sign\": $fa-var-yen-sign,\n \"cny\": $fa-var-cny,\n \"jpy\": $fa-var-jpy,\n \"rmb\": $fa-var-rmb,\n \"yen\": $fa-var-yen,\n \"ruble-sign\": $fa-var-ruble-sign,\n \"rouble\": $fa-var-rouble,\n \"rub\": $fa-var-rub,\n \"ruble\": $fa-var-ruble,\n \"sun\": $fa-var-sun,\n \"guitar\": $fa-var-guitar,\n \"face-laugh-wink\": $fa-var-face-laugh-wink,\n \"laugh-wink\": $fa-var-laugh-wink,\n \"horse-head\": $fa-var-horse-head,\n \"bore-hole\": $fa-var-bore-hole,\n \"industry\": $fa-var-industry,\n \"circle-down\": $fa-var-circle-down,\n \"arrow-alt-circle-down\": $fa-var-arrow-alt-circle-down,\n \"arrows-turn-to-dots\": $fa-var-arrows-turn-to-dots,\n \"florin-sign\": $fa-var-florin-sign,\n \"arrow-down-short-wide\": $fa-var-arrow-down-short-wide,\n \"sort-amount-desc\": $fa-var-sort-amount-desc,\n \"sort-amount-down-alt\": $fa-var-sort-amount-down-alt,\n \"less-than\": $fa-var-less-than,\n \"angle-down\": $fa-var-angle-down,\n \"car-tunnel\": $fa-var-car-tunnel,\n \"head-side-cough\": $fa-var-head-side-cough,\n \"grip-lines\": $fa-var-grip-lines,\n \"thumbs-down\": $fa-var-thumbs-down,\n \"user-lock\": $fa-var-user-lock,\n \"arrow-right-long\": $fa-var-arrow-right-long,\n \"long-arrow-right\": $fa-var-long-arrow-right,\n \"anchor-circle-xmark\": $fa-var-anchor-circle-xmark,\n \"ellipsis\": $fa-var-ellipsis,\n \"ellipsis-h\": $fa-var-ellipsis-h,\n \"chess-pawn\": $fa-var-chess-pawn,\n \"kit-medical\": $fa-var-kit-medical,\n \"first-aid\": $fa-var-first-aid,\n \"person-through-window\": $fa-var-person-through-window,\n \"toolbox\": $fa-var-toolbox,\n \"hands-holding-circle\": $fa-var-hands-holding-circle,\n \"bug\": $fa-var-bug,\n \"credit-card\": $fa-var-credit-card,\n \"credit-card-alt\": $fa-var-credit-card-alt,\n \"car\": $fa-var-car,\n \"automobile\": $fa-var-automobile,\n \"hand-holding-hand\": $fa-var-hand-holding-hand,\n \"book-open-reader\": $fa-var-book-open-reader,\n \"book-reader\": $fa-var-book-reader,\n \"mountain-sun\": $fa-var-mountain-sun,\n \"arrows-left-right-to-line\": $fa-var-arrows-left-right-to-line,\n \"dice-d20\": $fa-var-dice-d20,\n \"truck-droplet\": $fa-var-truck-droplet,\n \"file-circle-xmark\": $fa-var-file-circle-xmark,\n \"temperature-arrow-up\": $fa-var-temperature-arrow-up,\n \"temperature-up\": $fa-var-temperature-up,\n \"medal\": $fa-var-medal,\n \"bed\": $fa-var-bed,\n \"square-h\": $fa-var-square-h,\n \"h-square\": $fa-var-h-square,\n \"podcast\": $fa-var-podcast,\n \"temperature-full\": $fa-var-temperature-full,\n \"temperature-4\": $fa-var-temperature-4,\n \"thermometer-4\": $fa-var-thermometer-4,\n \"thermometer-full\": $fa-var-thermometer-full,\n \"bell\": $fa-var-bell,\n \"superscript\": $fa-var-superscript,\n \"plug-circle-xmark\": $fa-var-plug-circle-xmark,\n \"star-of-life\": $fa-var-star-of-life,\n \"phone-slash\": $fa-var-phone-slash,\n \"paint-roller\": $fa-var-paint-roller,\n \"handshake-angle\": $fa-var-handshake-angle,\n \"hands-helping\": $fa-var-hands-helping,\n \"location-dot\": $fa-var-location-dot,\n \"map-marker-alt\": $fa-var-map-marker-alt,\n \"file\": $fa-var-file,\n \"greater-than\": $fa-var-greater-than,\n \"person-swimming\": $fa-var-person-swimming,\n \"swimmer\": $fa-var-swimmer,\n \"arrow-down\": $fa-var-arrow-down,\n \"droplet\": $fa-var-droplet,\n \"tint\": $fa-var-tint,\n \"eraser\": $fa-var-eraser,\n \"earth-americas\": $fa-var-earth-americas,\n \"earth\": $fa-var-earth,\n \"earth-america\": $fa-var-earth-america,\n \"globe-americas\": $fa-var-globe-americas,\n \"person-burst\": $fa-var-person-burst,\n \"dove\": $fa-var-dove,\n \"battery-empty\": $fa-var-battery-empty,\n \"battery-0\": $fa-var-battery-0,\n \"socks\": $fa-var-socks,\n \"inbox\": $fa-var-inbox,\n \"section\": $fa-var-section,\n \"gauge-high\": $fa-var-gauge-high,\n \"tachometer-alt\": $fa-var-tachometer-alt,\n \"tachometer-alt-fast\": $fa-var-tachometer-alt-fast,\n \"envelope-open-text\": $fa-var-envelope-open-text,\n \"hospital\": $fa-var-hospital,\n \"hospital-alt\": $fa-var-hospital-alt,\n \"hospital-wide\": $fa-var-hospital-wide,\n \"wine-bottle\": $fa-var-wine-bottle,\n \"chess-rook\": $fa-var-chess-rook,\n \"bars-staggered\": $fa-var-bars-staggered,\n \"reorder\": $fa-var-reorder,\n \"stream\": $fa-var-stream,\n \"dharmachakra\": $fa-var-dharmachakra,\n \"hotdog\": $fa-var-hotdog,\n \"person-walking-with-cane\": $fa-var-person-walking-with-cane,\n \"blind\": $fa-var-blind,\n \"drum\": $fa-var-drum,\n \"ice-cream\": $fa-var-ice-cream,\n \"heart-circle-bolt\": $fa-var-heart-circle-bolt,\n \"fax\": $fa-var-fax,\n \"paragraph\": $fa-var-paragraph,\n \"check-to-slot\": $fa-var-check-to-slot,\n \"vote-yea\": $fa-var-vote-yea,\n \"star-half\": $fa-var-star-half,\n \"boxes-stacked\": $fa-var-boxes-stacked,\n \"boxes\": $fa-var-boxes,\n \"boxes-alt\": $fa-var-boxes-alt,\n \"link\": $fa-var-link,\n \"chain\": $fa-var-chain,\n \"ear-listen\": $fa-var-ear-listen,\n \"assistive-listening-systems\": $fa-var-assistive-listening-systems,\n \"tree-city\": $fa-var-tree-city,\n \"play\": $fa-var-play,\n \"font\": $fa-var-font,\n \"table-cells-row-lock\": $fa-var-table-cells-row-lock,\n \"rupiah-sign\": $fa-var-rupiah-sign,\n \"magnifying-glass\": $fa-var-magnifying-glass,\n \"search\": $fa-var-search,\n \"table-tennis-paddle-ball\": $fa-var-table-tennis-paddle-ball,\n \"ping-pong-paddle-ball\": $fa-var-ping-pong-paddle-ball,\n \"table-tennis\": $fa-var-table-tennis,\n \"person-dots-from-line\": $fa-var-person-dots-from-line,\n \"diagnoses\": $fa-var-diagnoses,\n \"trash-can-arrow-up\": $fa-var-trash-can-arrow-up,\n \"trash-restore-alt\": $fa-var-trash-restore-alt,\n \"naira-sign\": $fa-var-naira-sign,\n \"cart-arrow-down\": $fa-var-cart-arrow-down,\n \"walkie-talkie\": $fa-var-walkie-talkie,\n \"file-pen\": $fa-var-file-pen,\n \"file-edit\": $fa-var-file-edit,\n \"receipt\": $fa-var-receipt,\n \"square-pen\": $fa-var-square-pen,\n \"pen-square\": $fa-var-pen-square,\n \"pencil-square\": $fa-var-pencil-square,\n \"suitcase-rolling\": $fa-var-suitcase-rolling,\n \"person-circle-exclamation\": $fa-var-person-circle-exclamation,\n \"chevron-down\": $fa-var-chevron-down,\n \"battery-full\": $fa-var-battery-full,\n \"battery\": $fa-var-battery,\n \"battery-5\": $fa-var-battery-5,\n \"skull-crossbones\": $fa-var-skull-crossbones,\n \"code-compare\": $fa-var-code-compare,\n \"list-ul\": $fa-var-list-ul,\n \"list-dots\": $fa-var-list-dots,\n \"school-lock\": $fa-var-school-lock,\n \"tower-cell\": $fa-var-tower-cell,\n \"down-long\": $fa-var-down-long,\n \"long-arrow-alt-down\": $fa-var-long-arrow-alt-down,\n \"ranking-star\": $fa-var-ranking-star,\n \"chess-king\": $fa-var-chess-king,\n \"person-harassing\": $fa-var-person-harassing,\n \"brazilian-real-sign\": $fa-var-brazilian-real-sign,\n \"landmark-dome\": $fa-var-landmark-dome,\n \"landmark-alt\": $fa-var-landmark-alt,\n \"arrow-up\": $fa-var-arrow-up,\n \"tv\": $fa-var-tv,\n \"television\": $fa-var-television,\n \"tv-alt\": $fa-var-tv-alt,\n \"shrimp\": $fa-var-shrimp,\n \"list-check\": $fa-var-list-check,\n \"tasks\": $fa-var-tasks,\n \"jug-detergent\": $fa-var-jug-detergent,\n \"circle-user\": $fa-var-circle-user,\n \"user-circle\": $fa-var-user-circle,\n \"user-shield\": $fa-var-user-shield,\n \"wind\": $fa-var-wind,\n \"car-burst\": $fa-var-car-burst,\n \"car-crash\": $fa-var-car-crash,\n \"y\": $fa-var-y,\n \"person-snowboarding\": $fa-var-person-snowboarding,\n \"snowboarding\": $fa-var-snowboarding,\n \"truck-fast\": $fa-var-truck-fast,\n \"shipping-fast\": $fa-var-shipping-fast,\n \"fish\": $fa-var-fish,\n \"user-graduate\": $fa-var-user-graduate,\n \"circle-half-stroke\": $fa-var-circle-half-stroke,\n \"adjust\": $fa-var-adjust,\n \"clapperboard\": $fa-var-clapperboard,\n \"circle-radiation\": $fa-var-circle-radiation,\n \"radiation-alt\": $fa-var-radiation-alt,\n \"baseball\": $fa-var-baseball,\n \"baseball-ball\": $fa-var-baseball-ball,\n \"jet-fighter-up\": $fa-var-jet-fighter-up,\n \"diagram-project\": $fa-var-diagram-project,\n \"project-diagram\": $fa-var-project-diagram,\n \"copy\": $fa-var-copy,\n \"volume-xmark\": $fa-var-volume-xmark,\n \"volume-mute\": $fa-var-volume-mute,\n \"volume-times\": $fa-var-volume-times,\n \"hand-sparkles\": $fa-var-hand-sparkles,\n \"grip\": $fa-var-grip,\n \"grip-horizontal\": $fa-var-grip-horizontal,\n \"share-from-square\": $fa-var-share-from-square,\n \"share-square\": $fa-var-share-square,\n \"child-combatant\": $fa-var-child-combatant,\n \"child-rifle\": $fa-var-child-rifle,\n \"gun\": $fa-var-gun,\n \"square-phone\": $fa-var-square-phone,\n \"phone-square\": $fa-var-phone-square,\n \"plus\": $fa-var-plus,\n \"add\": $fa-var-add,\n \"expand\": $fa-var-expand,\n \"computer\": $fa-var-computer,\n \"xmark\": $fa-var-xmark,\n \"close\": $fa-var-close,\n \"multiply\": $fa-var-multiply,\n \"remove\": $fa-var-remove,\n \"times\": $fa-var-times,\n \"arrows-up-down-left-right\": $fa-var-arrows-up-down-left-right,\n \"arrows\": $fa-var-arrows,\n \"chalkboard-user\": $fa-var-chalkboard-user,\n \"chalkboard-teacher\": $fa-var-chalkboard-teacher,\n \"peso-sign\": $fa-var-peso-sign,\n \"building-shield\": $fa-var-building-shield,\n \"baby\": $fa-var-baby,\n \"users-line\": $fa-var-users-line,\n \"quote-left\": $fa-var-quote-left,\n \"quote-left-alt\": $fa-var-quote-left-alt,\n \"tractor\": $fa-var-tractor,\n \"trash-arrow-up\": $fa-var-trash-arrow-up,\n \"trash-restore\": $fa-var-trash-restore,\n \"arrow-down-up-lock\": $fa-var-arrow-down-up-lock,\n \"lines-leaning\": $fa-var-lines-leaning,\n \"ruler-combined\": $fa-var-ruler-combined,\n \"copyright\": $fa-var-copyright,\n \"equals\": $fa-var-equals,\n \"blender\": $fa-var-blender,\n \"teeth\": $fa-var-teeth,\n \"shekel-sign\": $fa-var-shekel-sign,\n \"ils\": $fa-var-ils,\n \"shekel\": $fa-var-shekel,\n \"sheqel\": $fa-var-sheqel,\n \"sheqel-sign\": $fa-var-sheqel-sign,\n \"map\": $fa-var-map,\n \"rocket\": $fa-var-rocket,\n \"photo-film\": $fa-var-photo-film,\n \"photo-video\": $fa-var-photo-video,\n \"folder-minus\": $fa-var-folder-minus,\n \"hexagon-nodes-bolt\": $fa-var-hexagon-nodes-bolt,\n \"store\": $fa-var-store,\n \"arrow-trend-up\": $fa-var-arrow-trend-up,\n \"plug-circle-minus\": $fa-var-plug-circle-minus,\n \"sign-hanging\": $fa-var-sign-hanging,\n \"sign\": $fa-var-sign,\n \"bezier-curve\": $fa-var-bezier-curve,\n \"bell-slash\": $fa-var-bell-slash,\n \"tablet\": $fa-var-tablet,\n \"tablet-android\": $fa-var-tablet-android,\n \"school-flag\": $fa-var-school-flag,\n \"fill\": $fa-var-fill,\n \"angle-up\": $fa-var-angle-up,\n \"drumstick-bite\": $fa-var-drumstick-bite,\n \"holly-berry\": $fa-var-holly-berry,\n \"chevron-left\": $fa-var-chevron-left,\n \"bacteria\": $fa-var-bacteria,\n \"hand-lizard\": $fa-var-hand-lizard,\n \"notdef\": $fa-var-notdef,\n \"disease\": $fa-var-disease,\n \"briefcase-medical\": $fa-var-briefcase-medical,\n \"genderless\": $fa-var-genderless,\n \"chevron-right\": $fa-var-chevron-right,\n \"retweet\": $fa-var-retweet,\n \"car-rear\": $fa-var-car-rear,\n \"car-alt\": $fa-var-car-alt,\n \"pump-soap\": $fa-var-pump-soap,\n \"video-slash\": $fa-var-video-slash,\n \"battery-quarter\": $fa-var-battery-quarter,\n \"battery-2\": $fa-var-battery-2,\n \"radio\": $fa-var-radio,\n \"baby-carriage\": $fa-var-baby-carriage,\n \"carriage-baby\": $fa-var-carriage-baby,\n \"traffic-light\": $fa-var-traffic-light,\n \"thermometer\": $fa-var-thermometer,\n \"vr-cardboard\": $fa-var-vr-cardboard,\n \"hand-middle-finger\": $fa-var-hand-middle-finger,\n \"percent\": $fa-var-percent,\n \"percentage\": $fa-var-percentage,\n \"truck-moving\": $fa-var-truck-moving,\n \"glass-water-droplet\": $fa-var-glass-water-droplet,\n \"display\": $fa-var-display,\n \"face-smile\": $fa-var-face-smile,\n \"smile\": $fa-var-smile,\n \"thumbtack\": $fa-var-thumbtack,\n \"thumb-tack\": $fa-var-thumb-tack,\n \"trophy\": $fa-var-trophy,\n \"person-praying\": $fa-var-person-praying,\n \"pray\": $fa-var-pray,\n \"hammer\": $fa-var-hammer,\n \"hand-peace\": $fa-var-hand-peace,\n \"rotate\": $fa-var-rotate,\n \"sync-alt\": $fa-var-sync-alt,\n \"spinner\": $fa-var-spinner,\n \"robot\": $fa-var-robot,\n \"peace\": $fa-var-peace,\n \"gears\": $fa-var-gears,\n \"cogs\": $fa-var-cogs,\n \"warehouse\": $fa-var-warehouse,\n \"arrow-up-right-dots\": $fa-var-arrow-up-right-dots,\n \"splotch\": $fa-var-splotch,\n \"face-grin-hearts\": $fa-var-face-grin-hearts,\n \"grin-hearts\": $fa-var-grin-hearts,\n \"dice-four\": $fa-var-dice-four,\n \"sim-card\": $fa-var-sim-card,\n \"transgender\": $fa-var-transgender,\n \"transgender-alt\": $fa-var-transgender-alt,\n \"mercury\": $fa-var-mercury,\n \"arrow-turn-down\": $fa-var-arrow-turn-down,\n \"level-down\": $fa-var-level-down,\n \"person-falling-burst\": $fa-var-person-falling-burst,\n \"award\": $fa-var-award,\n \"ticket-simple\": $fa-var-ticket-simple,\n \"ticket-alt\": $fa-var-ticket-alt,\n \"building\": $fa-var-building,\n \"angles-left\": $fa-var-angles-left,\n \"angle-double-left\": $fa-var-angle-double-left,\n \"qrcode\": $fa-var-qrcode,\n \"clock-rotate-left\": $fa-var-clock-rotate-left,\n \"history\": $fa-var-history,\n \"face-grin-beam-sweat\": $fa-var-face-grin-beam-sweat,\n \"grin-beam-sweat\": $fa-var-grin-beam-sweat,\n \"file-export\": $fa-var-file-export,\n \"arrow-right-from-file\": $fa-var-arrow-right-from-file,\n \"shield\": $fa-var-shield,\n \"shield-blank\": $fa-var-shield-blank,\n \"arrow-up-short-wide\": $fa-var-arrow-up-short-wide,\n \"sort-amount-up-alt\": $fa-var-sort-amount-up-alt,\n \"comment-nodes\": $fa-var-comment-nodes,\n \"house-medical\": $fa-var-house-medical,\n \"golf-ball-tee\": $fa-var-golf-ball-tee,\n \"golf-ball\": $fa-var-golf-ball,\n \"circle-chevron-left\": $fa-var-circle-chevron-left,\n \"chevron-circle-left\": $fa-var-chevron-circle-left,\n \"house-chimney-window\": $fa-var-house-chimney-window,\n \"pen-nib\": $fa-var-pen-nib,\n \"tent-arrow-turn-left\": $fa-var-tent-arrow-turn-left,\n \"tents\": $fa-var-tents,\n \"wand-magic\": $fa-var-wand-magic,\n \"magic\": $fa-var-magic,\n \"dog\": $fa-var-dog,\n \"carrot\": $fa-var-carrot,\n \"moon\": $fa-var-moon,\n \"wine-glass-empty\": $fa-var-wine-glass-empty,\n \"wine-glass-alt\": $fa-var-wine-glass-alt,\n \"cheese\": $fa-var-cheese,\n \"yin-yang\": $fa-var-yin-yang,\n \"music\": $fa-var-music,\n \"code-commit\": $fa-var-code-commit,\n \"temperature-low\": $fa-var-temperature-low,\n \"person-biking\": $fa-var-person-biking,\n \"biking\": $fa-var-biking,\n \"broom\": $fa-var-broom,\n \"shield-heart\": $fa-var-shield-heart,\n \"gopuram\": $fa-var-gopuram,\n \"earth-oceania\": $fa-var-earth-oceania,\n \"globe-oceania\": $fa-var-globe-oceania,\n \"square-xmark\": $fa-var-square-xmark,\n \"times-square\": $fa-var-times-square,\n \"xmark-square\": $fa-var-xmark-square,\n \"hashtag\": $fa-var-hashtag,\n \"up-right-and-down-left-from-center\": $fa-var-up-right-and-down-left-from-center,\n \"expand-alt\": $fa-var-expand-alt,\n \"oil-can\": $fa-var-oil-can,\n \"t\": $fa-var-t,\n \"hippo\": $fa-var-hippo,\n \"chart-column\": $fa-var-chart-column,\n \"infinity\": $fa-var-infinity,\n \"vial-circle-check\": $fa-var-vial-circle-check,\n \"person-arrow-down-to-line\": $fa-var-person-arrow-down-to-line,\n \"voicemail\": $fa-var-voicemail,\n \"fan\": $fa-var-fan,\n \"person-walking-luggage\": $fa-var-person-walking-luggage,\n \"up-down\": $fa-var-up-down,\n \"arrows-alt-v\": $fa-var-arrows-alt-v,\n \"cloud-moon-rain\": $fa-var-cloud-moon-rain,\n \"calendar\": $fa-var-calendar,\n \"trailer\": $fa-var-trailer,\n \"bahai\": $fa-var-bahai,\n \"haykal\": $fa-var-haykal,\n \"sd-card\": $fa-var-sd-card,\n \"dragon\": $fa-var-dragon,\n \"shoe-prints\": $fa-var-shoe-prints,\n \"circle-plus\": $fa-var-circle-plus,\n \"plus-circle\": $fa-var-plus-circle,\n \"face-grin-tongue-wink\": $fa-var-face-grin-tongue-wink,\n \"grin-tongue-wink\": $fa-var-grin-tongue-wink,\n \"hand-holding\": $fa-var-hand-holding,\n \"plug-circle-exclamation\": $fa-var-plug-circle-exclamation,\n \"link-slash\": $fa-var-link-slash,\n \"chain-broken\": $fa-var-chain-broken,\n \"chain-slash\": $fa-var-chain-slash,\n \"unlink\": $fa-var-unlink,\n \"clone\": $fa-var-clone,\n \"person-walking-arrow-loop-left\": $fa-var-person-walking-arrow-loop-left,\n \"arrow-up-z-a\": $fa-var-arrow-up-z-a,\n \"sort-alpha-up-alt\": $fa-var-sort-alpha-up-alt,\n \"fire-flame-curved\": $fa-var-fire-flame-curved,\n \"fire-alt\": $fa-var-fire-alt,\n \"tornado\": $fa-var-tornado,\n \"file-circle-plus\": $fa-var-file-circle-plus,\n \"book-quran\": $fa-var-book-quran,\n \"quran\": $fa-var-quran,\n \"anchor\": $fa-var-anchor,\n \"border-all\": $fa-var-border-all,\n \"face-angry\": $fa-var-face-angry,\n \"angry\": $fa-var-angry,\n \"cookie-bite\": $fa-var-cookie-bite,\n \"arrow-trend-down\": $fa-var-arrow-trend-down,\n \"rss\": $fa-var-rss,\n \"feed\": $fa-var-feed,\n \"draw-polygon\": $fa-var-draw-polygon,\n \"scale-balanced\": $fa-var-scale-balanced,\n \"balance-scale\": $fa-var-balance-scale,\n \"gauge-simple-high\": $fa-var-gauge-simple-high,\n \"tachometer\": $fa-var-tachometer,\n \"tachometer-fast\": $fa-var-tachometer-fast,\n \"shower\": $fa-var-shower,\n \"desktop\": $fa-var-desktop,\n \"desktop-alt\": $fa-var-desktop-alt,\n \"m\": $fa-var-m,\n \"table-list\": $fa-var-table-list,\n \"th-list\": $fa-var-th-list,\n \"comment-sms\": $fa-var-comment-sms,\n \"sms\": $fa-var-sms,\n \"book\": $fa-var-book,\n \"user-plus\": $fa-var-user-plus,\n \"check\": $fa-var-check,\n \"battery-three-quarters\": $fa-var-battery-three-quarters,\n \"battery-4\": $fa-var-battery-4,\n \"house-circle-check\": $fa-var-house-circle-check,\n \"angle-left\": $fa-var-angle-left,\n \"diagram-successor\": $fa-var-diagram-successor,\n \"truck-arrow-right\": $fa-var-truck-arrow-right,\n \"arrows-split-up-and-left\": $fa-var-arrows-split-up-and-left,\n \"hand-fist\": $fa-var-hand-fist,\n \"fist-raised\": $fa-var-fist-raised,\n \"cloud-moon\": $fa-var-cloud-moon,\n \"briefcase\": $fa-var-briefcase,\n \"person-falling\": $fa-var-person-falling,\n \"image-portrait\": $fa-var-image-portrait,\n \"portrait\": $fa-var-portrait,\n \"user-tag\": $fa-var-user-tag,\n \"rug\": $fa-var-rug,\n \"earth-europe\": $fa-var-earth-europe,\n \"globe-europe\": $fa-var-globe-europe,\n \"cart-flatbed-suitcase\": $fa-var-cart-flatbed-suitcase,\n \"luggage-cart\": $fa-var-luggage-cart,\n \"rectangle-xmark\": $fa-var-rectangle-xmark,\n \"rectangle-times\": $fa-var-rectangle-times,\n \"times-rectangle\": $fa-var-times-rectangle,\n \"window-close\": $fa-var-window-close,\n \"baht-sign\": $fa-var-baht-sign,\n \"book-open\": $fa-var-book-open,\n \"book-journal-whills\": $fa-var-book-journal-whills,\n \"journal-whills\": $fa-var-journal-whills,\n \"handcuffs\": $fa-var-handcuffs,\n \"triangle-exclamation\": $fa-var-triangle-exclamation,\n \"exclamation-triangle\": $fa-var-exclamation-triangle,\n \"warning\": $fa-var-warning,\n \"database\": $fa-var-database,\n \"share\": $fa-var-share,\n \"mail-forward\": $fa-var-mail-forward,\n \"bottle-droplet\": $fa-var-bottle-droplet,\n \"mask-face\": $fa-var-mask-face,\n \"hill-rockslide\": $fa-var-hill-rockslide,\n \"right-left\": $fa-var-right-left,\n \"exchange-alt\": $fa-var-exchange-alt,\n \"paper-plane\": $fa-var-paper-plane,\n \"road-circle-exclamation\": $fa-var-road-circle-exclamation,\n \"dungeon\": $fa-var-dungeon,\n \"align-right\": $fa-var-align-right,\n \"money-bill-1-wave\": $fa-var-money-bill-1-wave,\n \"money-bill-wave-alt\": $fa-var-money-bill-wave-alt,\n \"life-ring\": $fa-var-life-ring,\n \"hands\": $fa-var-hands,\n \"sign-language\": $fa-var-sign-language,\n \"signing\": $fa-var-signing,\n \"calendar-day\": $fa-var-calendar-day,\n \"water-ladder\": $fa-var-water-ladder,\n \"ladder-water\": $fa-var-ladder-water,\n \"swimming-pool\": $fa-var-swimming-pool,\n \"arrows-up-down\": $fa-var-arrows-up-down,\n \"arrows-v\": $fa-var-arrows-v,\n \"face-grimace\": $fa-var-face-grimace,\n \"grimace\": $fa-var-grimace,\n \"wheelchair-move\": $fa-var-wheelchair-move,\n \"wheelchair-alt\": $fa-var-wheelchair-alt,\n \"turn-down\": $fa-var-turn-down,\n \"level-down-alt\": $fa-var-level-down-alt,\n \"person-walking-arrow-right\": $fa-var-person-walking-arrow-right,\n \"square-envelope\": $fa-var-square-envelope,\n \"envelope-square\": $fa-var-envelope-square,\n \"dice\": $fa-var-dice,\n \"bowling-ball\": $fa-var-bowling-ball,\n \"brain\": $fa-var-brain,\n \"bandage\": $fa-var-bandage,\n \"band-aid\": $fa-var-band-aid,\n \"calendar-minus\": $fa-var-calendar-minus,\n \"circle-xmark\": $fa-var-circle-xmark,\n \"times-circle\": $fa-var-times-circle,\n \"xmark-circle\": $fa-var-xmark-circle,\n \"gifts\": $fa-var-gifts,\n \"hotel\": $fa-var-hotel,\n \"earth-asia\": $fa-var-earth-asia,\n \"globe-asia\": $fa-var-globe-asia,\n \"id-card-clip\": $fa-var-id-card-clip,\n \"id-card-alt\": $fa-var-id-card-alt,\n \"magnifying-glass-plus\": $fa-var-magnifying-glass-plus,\n \"search-plus\": $fa-var-search-plus,\n \"thumbs-up\": $fa-var-thumbs-up,\n \"user-clock\": $fa-var-user-clock,\n \"hand-dots\": $fa-var-hand-dots,\n \"allergies\": $fa-var-allergies,\n \"file-invoice\": $fa-var-file-invoice,\n \"window-minimize\": $fa-var-window-minimize,\n \"mug-saucer\": $fa-var-mug-saucer,\n \"coffee\": $fa-var-coffee,\n \"brush\": $fa-var-brush,\n \"file-half-dashed\": $fa-var-file-half-dashed,\n \"mask\": $fa-var-mask,\n \"magnifying-glass-minus\": $fa-var-magnifying-glass-minus,\n \"search-minus\": $fa-var-search-minus,\n \"ruler-vertical\": $fa-var-ruler-vertical,\n \"user-large\": $fa-var-user-large,\n \"user-alt\": $fa-var-user-alt,\n \"train-tram\": $fa-var-train-tram,\n \"user-nurse\": $fa-var-user-nurse,\n \"syringe\": $fa-var-syringe,\n \"cloud-sun\": $fa-var-cloud-sun,\n \"stopwatch-20\": $fa-var-stopwatch-20,\n \"square-full\": $fa-var-square-full,\n \"magnet\": $fa-var-magnet,\n \"jar\": $fa-var-jar,\n \"note-sticky\": $fa-var-note-sticky,\n \"sticky-note\": $fa-var-sticky-note,\n \"bug-slash\": $fa-var-bug-slash,\n \"arrow-up-from-water-pump\": $fa-var-arrow-up-from-water-pump,\n \"bone\": $fa-var-bone,\n \"table-cells-row-unlock\": $fa-var-table-cells-row-unlock,\n \"user-injured\": $fa-var-user-injured,\n \"face-sad-tear\": $fa-var-face-sad-tear,\n \"sad-tear\": $fa-var-sad-tear,\n \"plane\": $fa-var-plane,\n \"tent-arrows-down\": $fa-var-tent-arrows-down,\n \"exclamation\": $fa-var-exclamation,\n \"arrows-spin\": $fa-var-arrows-spin,\n \"print\": $fa-var-print,\n \"turkish-lira-sign\": $fa-var-turkish-lira-sign,\n \"try\": $fa-var-try,\n \"turkish-lira\": $fa-var-turkish-lira,\n \"dollar-sign\": $fa-var-dollar-sign,\n \"dollar\": $fa-var-dollar,\n \"usd\": $fa-var-usd,\n \"x\": $fa-var-x,\n \"magnifying-glass-dollar\": $fa-var-magnifying-glass-dollar,\n \"search-dollar\": $fa-var-search-dollar,\n \"users-gear\": $fa-var-users-gear,\n \"users-cog\": $fa-var-users-cog,\n \"person-military-pointing\": $fa-var-person-military-pointing,\n \"building-columns\": $fa-var-building-columns,\n \"bank\": $fa-var-bank,\n \"institution\": $fa-var-institution,\n \"museum\": $fa-var-museum,\n \"university\": $fa-var-university,\n \"umbrella\": $fa-var-umbrella,\n \"trowel\": $fa-var-trowel,\n \"d\": $fa-var-d,\n \"stapler\": $fa-var-stapler,\n \"masks-theater\": $fa-var-masks-theater,\n \"theater-masks\": $fa-var-theater-masks,\n \"kip-sign\": $fa-var-kip-sign,\n \"hand-point-left\": $fa-var-hand-point-left,\n \"handshake-simple\": $fa-var-handshake-simple,\n \"handshake-alt\": $fa-var-handshake-alt,\n \"jet-fighter\": $fa-var-jet-fighter,\n \"fighter-jet\": $fa-var-fighter-jet,\n \"square-share-nodes\": $fa-var-square-share-nodes,\n \"share-alt-square\": $fa-var-share-alt-square,\n \"barcode\": $fa-var-barcode,\n \"plus-minus\": $fa-var-plus-minus,\n \"video\": $fa-var-video,\n \"video-camera\": $fa-var-video-camera,\n \"graduation-cap\": $fa-var-graduation-cap,\n \"mortar-board\": $fa-var-mortar-board,\n \"hand-holding-medical\": $fa-var-hand-holding-medical,\n \"person-circle-check\": $fa-var-person-circle-check,\n \"turn-up\": $fa-var-turn-up,\n \"level-up-alt\": $fa-var-level-up-alt,\n);\n\n$fa-brand-icons: (\n \"monero\": $fa-var-monero,\n \"hooli\": $fa-var-hooli,\n \"yelp\": $fa-var-yelp,\n \"cc-visa\": $fa-var-cc-visa,\n \"lastfm\": $fa-var-lastfm,\n \"shopware\": $fa-var-shopware,\n \"creative-commons-nc\": $fa-var-creative-commons-nc,\n \"aws\": $fa-var-aws,\n \"redhat\": $fa-var-redhat,\n \"yoast\": $fa-var-yoast,\n \"cloudflare\": $fa-var-cloudflare,\n \"ups\": $fa-var-ups,\n \"pixiv\": $fa-var-pixiv,\n \"wpexplorer\": $fa-var-wpexplorer,\n \"dyalog\": $fa-var-dyalog,\n \"bity\": $fa-var-bity,\n \"stackpath\": $fa-var-stackpath,\n \"buysellads\": $fa-var-buysellads,\n \"first-order\": $fa-var-first-order,\n \"modx\": $fa-var-modx,\n \"guilded\": $fa-var-guilded,\n \"vnv\": $fa-var-vnv,\n \"square-js\": $fa-var-square-js,\n \"js-square\": $fa-var-js-square,\n \"microsoft\": $fa-var-microsoft,\n \"qq\": $fa-var-qq,\n \"orcid\": $fa-var-orcid,\n \"java\": $fa-var-java,\n \"invision\": $fa-var-invision,\n \"creative-commons-pd-alt\": $fa-var-creative-commons-pd-alt,\n \"centercode\": $fa-var-centercode,\n \"glide-g\": $fa-var-glide-g,\n \"drupal\": $fa-var-drupal,\n \"jxl\": $fa-var-jxl,\n \"dart-lang\": $fa-var-dart-lang,\n \"hire-a-helper\": $fa-var-hire-a-helper,\n \"creative-commons-by\": $fa-var-creative-commons-by,\n \"unity\": $fa-var-unity,\n \"whmcs\": $fa-var-whmcs,\n \"rocketchat\": $fa-var-rocketchat,\n \"vk\": $fa-var-vk,\n \"untappd\": $fa-var-untappd,\n \"mailchimp\": $fa-var-mailchimp,\n \"css3-alt\": $fa-var-css3-alt,\n \"square-reddit\": $fa-var-square-reddit,\n \"reddit-square\": $fa-var-reddit-square,\n \"vimeo-v\": $fa-var-vimeo-v,\n \"contao\": $fa-var-contao,\n \"square-font-awesome\": $fa-var-square-font-awesome,\n \"deskpro\": $fa-var-deskpro,\n \"brave\": $fa-var-brave,\n \"sistrix\": $fa-var-sistrix,\n \"square-instagram\": $fa-var-square-instagram,\n \"instagram-square\": $fa-var-instagram-square,\n \"battle-net\": $fa-var-battle-net,\n \"the-red-yeti\": $fa-var-the-red-yeti,\n \"square-hacker-news\": $fa-var-square-hacker-news,\n \"hacker-news-square\": $fa-var-hacker-news-square,\n \"edge\": $fa-var-edge,\n \"threads\": $fa-var-threads,\n \"napster\": $fa-var-napster,\n \"square-snapchat\": $fa-var-square-snapchat,\n \"snapchat-square\": $fa-var-snapchat-square,\n \"google-plus-g\": $fa-var-google-plus-g,\n \"artstation\": $fa-var-artstation,\n \"markdown\": $fa-var-markdown,\n \"sourcetree\": $fa-var-sourcetree,\n \"google-plus\": $fa-var-google-plus,\n \"diaspora\": $fa-var-diaspora,\n \"foursquare\": $fa-var-foursquare,\n \"stack-overflow\": $fa-var-stack-overflow,\n \"github-alt\": $fa-var-github-alt,\n \"phoenix-squadron\": $fa-var-phoenix-squadron,\n \"pagelines\": $fa-var-pagelines,\n \"algolia\": $fa-var-algolia,\n \"red-river\": $fa-var-red-river,\n \"creative-commons-sa\": $fa-var-creative-commons-sa,\n \"safari\": $fa-var-safari,\n \"google\": $fa-var-google,\n \"square-font-awesome-stroke\": $fa-var-square-font-awesome-stroke,\n \"font-awesome-alt\": $fa-var-font-awesome-alt,\n \"atlassian\": $fa-var-atlassian,\n \"linkedin-in\": $fa-var-linkedin-in,\n \"digital-ocean\": $fa-var-digital-ocean,\n \"nimblr\": $fa-var-nimblr,\n \"chromecast\": $fa-var-chromecast,\n \"evernote\": $fa-var-evernote,\n \"hacker-news\": $fa-var-hacker-news,\n \"creative-commons-sampling\": $fa-var-creative-commons-sampling,\n \"adversal\": $fa-var-adversal,\n \"creative-commons\": $fa-var-creative-commons,\n \"watchman-monitoring\": $fa-var-watchman-monitoring,\n \"fonticons\": $fa-var-fonticons,\n \"weixin\": $fa-var-weixin,\n \"shirtsinbulk\": $fa-var-shirtsinbulk,\n \"codepen\": $fa-var-codepen,\n \"git-alt\": $fa-var-git-alt,\n \"lyft\": $fa-var-lyft,\n \"rev\": $fa-var-rev,\n \"windows\": $fa-var-windows,\n \"wizards-of-the-coast\": $fa-var-wizards-of-the-coast,\n \"square-viadeo\": $fa-var-square-viadeo,\n \"viadeo-square\": $fa-var-viadeo-square,\n \"meetup\": $fa-var-meetup,\n \"centos\": $fa-var-centos,\n \"adn\": $fa-var-adn,\n \"cloudsmith\": $fa-var-cloudsmith,\n \"opensuse\": $fa-var-opensuse,\n \"pied-piper-alt\": $fa-var-pied-piper-alt,\n \"square-dribbble\": $fa-var-square-dribbble,\n \"dribbble-square\": $fa-var-dribbble-square,\n \"codiepie\": $fa-var-codiepie,\n \"node\": $fa-var-node,\n \"mix\": $fa-var-mix,\n \"steam\": $fa-var-steam,\n \"cc-apple-pay\": $fa-var-cc-apple-pay,\n \"scribd\": $fa-var-scribd,\n \"debian\": $fa-var-debian,\n \"openid\": $fa-var-openid,\n \"instalod\": $fa-var-instalod,\n \"files-pinwheel\": $fa-var-files-pinwheel,\n \"expeditedssl\": $fa-var-expeditedssl,\n \"sellcast\": $fa-var-sellcast,\n \"square-twitter\": $fa-var-square-twitter,\n \"twitter-square\": $fa-var-twitter-square,\n \"r-project\": $fa-var-r-project,\n \"delicious\": $fa-var-delicious,\n \"freebsd\": $fa-var-freebsd,\n \"vuejs\": $fa-var-vuejs,\n \"accusoft\": $fa-var-accusoft,\n \"ioxhost\": $fa-var-ioxhost,\n \"fonticons-fi\": $fa-var-fonticons-fi,\n \"app-store\": $fa-var-app-store,\n \"cc-mastercard\": $fa-var-cc-mastercard,\n \"itunes-note\": $fa-var-itunes-note,\n \"golang\": $fa-var-golang,\n \"kickstarter\": $fa-var-kickstarter,\n \"square-kickstarter\": $fa-var-square-kickstarter,\n \"grav\": $fa-var-grav,\n \"weibo\": $fa-var-weibo,\n \"uncharted\": $fa-var-uncharted,\n \"firstdraft\": $fa-var-firstdraft,\n \"square-youtube\": $fa-var-square-youtube,\n \"youtube-square\": $fa-var-youtube-square,\n \"wikipedia-w\": $fa-var-wikipedia-w,\n \"wpressr\": $fa-var-wpressr,\n \"rendact\": $fa-var-rendact,\n \"angellist\": $fa-var-angellist,\n \"galactic-republic\": $fa-var-galactic-republic,\n \"nfc-directional\": $fa-var-nfc-directional,\n \"skype\": $fa-var-skype,\n \"joget\": $fa-var-joget,\n \"fedora\": $fa-var-fedora,\n \"stripe-s\": $fa-var-stripe-s,\n \"meta\": $fa-var-meta,\n \"laravel\": $fa-var-laravel,\n \"hotjar\": $fa-var-hotjar,\n \"bluetooth-b\": $fa-var-bluetooth-b,\n \"square-letterboxd\": $fa-var-square-letterboxd,\n \"sticker-mule\": $fa-var-sticker-mule,\n \"creative-commons-zero\": $fa-var-creative-commons-zero,\n \"hips\": $fa-var-hips,\n \"css\": $fa-var-css,\n \"behance\": $fa-var-behance,\n \"reddit\": $fa-var-reddit,\n \"discord\": $fa-var-discord,\n \"chrome\": $fa-var-chrome,\n \"app-store-ios\": $fa-var-app-store-ios,\n \"cc-discover\": $fa-var-cc-discover,\n \"wpbeginner\": $fa-var-wpbeginner,\n \"confluence\": $fa-var-confluence,\n \"shoelace\": $fa-var-shoelace,\n \"mdb\": $fa-var-mdb,\n \"dochub\": $fa-var-dochub,\n \"accessible-icon\": $fa-var-accessible-icon,\n \"ebay\": $fa-var-ebay,\n \"amazon\": $fa-var-amazon,\n \"unsplash\": $fa-var-unsplash,\n \"yarn\": $fa-var-yarn,\n \"square-steam\": $fa-var-square-steam,\n \"steam-square\": $fa-var-steam-square,\n \"500px\": $fa-var-500px,\n \"square-vimeo\": $fa-var-square-vimeo,\n \"vimeo-square\": $fa-var-vimeo-square,\n \"asymmetrik\": $fa-var-asymmetrik,\n \"font-awesome\": $fa-var-font-awesome,\n \"font-awesome-flag\": $fa-var-font-awesome-flag,\n \"font-awesome-logo-full\": $fa-var-font-awesome-logo-full,\n \"gratipay\": $fa-var-gratipay,\n \"apple\": $fa-var-apple,\n \"hive\": $fa-var-hive,\n \"gitkraken\": $fa-var-gitkraken,\n \"keybase\": $fa-var-keybase,\n \"apple-pay\": $fa-var-apple-pay,\n \"padlet\": $fa-var-padlet,\n \"amazon-pay\": $fa-var-amazon-pay,\n \"square-github\": $fa-var-square-github,\n \"github-square\": $fa-var-github-square,\n \"stumbleupon\": $fa-var-stumbleupon,\n \"fedex\": $fa-var-fedex,\n \"phoenix-framework\": $fa-var-phoenix-framework,\n \"shopify\": $fa-var-shopify,\n \"neos\": $fa-var-neos,\n \"square-threads\": $fa-var-square-threads,\n \"hackerrank\": $fa-var-hackerrank,\n \"researchgate\": $fa-var-researchgate,\n \"swift\": $fa-var-swift,\n \"angular\": $fa-var-angular,\n \"speakap\": $fa-var-speakap,\n \"angrycreative\": $fa-var-angrycreative,\n \"y-combinator\": $fa-var-y-combinator,\n \"empire\": $fa-var-empire,\n \"envira\": $fa-var-envira,\n \"google-scholar\": $fa-var-google-scholar,\n \"square-gitlab\": $fa-var-square-gitlab,\n \"gitlab-square\": $fa-var-gitlab-square,\n \"studiovinari\": $fa-var-studiovinari,\n \"pied-piper\": $fa-var-pied-piper,\n \"wordpress\": $fa-var-wordpress,\n \"product-hunt\": $fa-var-product-hunt,\n \"firefox\": $fa-var-firefox,\n \"linode\": $fa-var-linode,\n \"goodreads\": $fa-var-goodreads,\n \"square-odnoklassniki\": $fa-var-square-odnoklassniki,\n \"odnoklassniki-square\": $fa-var-odnoklassniki-square,\n \"jsfiddle\": $fa-var-jsfiddle,\n \"sith\": $fa-var-sith,\n \"themeisle\": $fa-var-themeisle,\n \"page4\": $fa-var-page4,\n \"hashnode\": $fa-var-hashnode,\n \"react\": $fa-var-react,\n \"cc-paypal\": $fa-var-cc-paypal,\n \"squarespace\": $fa-var-squarespace,\n \"cc-stripe\": $fa-var-cc-stripe,\n \"creative-commons-share\": $fa-var-creative-commons-share,\n \"bitcoin\": $fa-var-bitcoin,\n \"keycdn\": $fa-var-keycdn,\n \"opera\": $fa-var-opera,\n \"itch-io\": $fa-var-itch-io,\n \"umbraco\": $fa-var-umbraco,\n \"galactic-senate\": $fa-var-galactic-senate,\n \"ubuntu\": $fa-var-ubuntu,\n \"draft2digital\": $fa-var-draft2digital,\n \"stripe\": $fa-var-stripe,\n \"houzz\": $fa-var-houzz,\n \"gg\": $fa-var-gg,\n \"dhl\": $fa-var-dhl,\n \"square-pinterest\": $fa-var-square-pinterest,\n \"pinterest-square\": $fa-var-pinterest-square,\n \"xing\": $fa-var-xing,\n \"blackberry\": $fa-var-blackberry,\n \"creative-commons-pd\": $fa-var-creative-commons-pd,\n \"playstation\": $fa-var-playstation,\n \"quinscape\": $fa-var-quinscape,\n \"less\": $fa-var-less,\n \"blogger-b\": $fa-var-blogger-b,\n \"opencart\": $fa-var-opencart,\n \"vine\": $fa-var-vine,\n \"signal-messenger\": $fa-var-signal-messenger,\n \"paypal\": $fa-var-paypal,\n \"gitlab\": $fa-var-gitlab,\n \"typo3\": $fa-var-typo3,\n \"reddit-alien\": $fa-var-reddit-alien,\n \"yahoo\": $fa-var-yahoo,\n \"dailymotion\": $fa-var-dailymotion,\n \"affiliatetheme\": $fa-var-affiliatetheme,\n \"pied-piper-pp\": $fa-var-pied-piper-pp,\n \"bootstrap\": $fa-var-bootstrap,\n \"odnoklassniki\": $fa-var-odnoklassniki,\n \"nfc-symbol\": $fa-var-nfc-symbol,\n \"mintbit\": $fa-var-mintbit,\n \"ethereum\": $fa-var-ethereum,\n \"speaker-deck\": $fa-var-speaker-deck,\n \"creative-commons-nc-eu\": $fa-var-creative-commons-nc-eu,\n \"patreon\": $fa-var-patreon,\n \"avianex\": $fa-var-avianex,\n \"ello\": $fa-var-ello,\n \"gofore\": $fa-var-gofore,\n \"bimobject\": $fa-var-bimobject,\n \"brave-reverse\": $fa-var-brave-reverse,\n \"facebook-f\": $fa-var-facebook-f,\n \"square-google-plus\": $fa-var-square-google-plus,\n \"google-plus-square\": $fa-var-google-plus-square,\n \"web-awesome\": $fa-var-web-awesome,\n \"mandalorian\": $fa-var-mandalorian,\n \"first-order-alt\": $fa-var-first-order-alt,\n \"osi\": $fa-var-osi,\n \"google-wallet\": $fa-var-google-wallet,\n \"d-and-d-beyond\": $fa-var-d-and-d-beyond,\n \"periscope\": $fa-var-periscope,\n \"fulcrum\": $fa-var-fulcrum,\n \"cloudscale\": $fa-var-cloudscale,\n \"forumbee\": $fa-var-forumbee,\n \"mizuni\": $fa-var-mizuni,\n \"schlix\": $fa-var-schlix,\n \"square-xing\": $fa-var-square-xing,\n \"xing-square\": $fa-var-xing-square,\n \"bandcamp\": $fa-var-bandcamp,\n \"wpforms\": $fa-var-wpforms,\n \"cloudversify\": $fa-var-cloudversify,\n \"usps\": $fa-var-usps,\n \"megaport\": $fa-var-megaport,\n \"magento\": $fa-var-magento,\n \"spotify\": $fa-var-spotify,\n \"optin-monster\": $fa-var-optin-monster,\n \"fly\": $fa-var-fly,\n \"square-bluesky\": $fa-var-square-bluesky,\n \"aviato\": $fa-var-aviato,\n \"itunes\": $fa-var-itunes,\n \"cuttlefish\": $fa-var-cuttlefish,\n \"blogger\": $fa-var-blogger,\n \"flickr\": $fa-var-flickr,\n \"viber\": $fa-var-viber,\n \"soundcloud\": $fa-var-soundcloud,\n \"digg\": $fa-var-digg,\n \"tencent-weibo\": $fa-var-tencent-weibo,\n \"letterboxd\": $fa-var-letterboxd,\n \"symfony\": $fa-var-symfony,\n \"maxcdn\": $fa-var-maxcdn,\n \"etsy\": $fa-var-etsy,\n \"facebook-messenger\": $fa-var-facebook-messenger,\n \"audible\": $fa-var-audible,\n \"think-peaks\": $fa-var-think-peaks,\n \"bilibili\": $fa-var-bilibili,\n \"erlang\": $fa-var-erlang,\n \"x-twitter\": $fa-var-x-twitter,\n \"cotton-bureau\": $fa-var-cotton-bureau,\n \"dashcube\": $fa-var-dashcube,\n \"42-group\": $fa-var-42-group,\n \"innosoft\": $fa-var-innosoft,\n \"stack-exchange\": $fa-var-stack-exchange,\n \"elementor\": $fa-var-elementor,\n \"square-pied-piper\": $fa-var-square-pied-piper,\n \"pied-piper-square\": $fa-var-pied-piper-square,\n \"creative-commons-nd\": $fa-var-creative-commons-nd,\n \"palfed\": $fa-var-palfed,\n \"superpowers\": $fa-var-superpowers,\n \"resolving\": $fa-var-resolving,\n \"xbox\": $fa-var-xbox,\n \"square-web-awesome-stroke\": $fa-var-square-web-awesome-stroke,\n \"searchengin\": $fa-var-searchengin,\n \"tiktok\": $fa-var-tiktok,\n \"square-facebook\": $fa-var-square-facebook,\n \"facebook-square\": $fa-var-facebook-square,\n \"renren\": $fa-var-renren,\n \"linux\": $fa-var-linux,\n \"glide\": $fa-var-glide,\n \"linkedin\": $fa-var-linkedin,\n \"hubspot\": $fa-var-hubspot,\n \"deploydog\": $fa-var-deploydog,\n \"twitch\": $fa-var-twitch,\n \"flutter\": $fa-var-flutter,\n \"ravelry\": $fa-var-ravelry,\n \"mixer\": $fa-var-mixer,\n \"square-lastfm\": $fa-var-square-lastfm,\n \"lastfm-square\": $fa-var-lastfm-square,\n \"vimeo\": $fa-var-vimeo,\n \"mendeley\": $fa-var-mendeley,\n \"uniregistry\": $fa-var-uniregistry,\n \"figma\": $fa-var-figma,\n \"creative-commons-remix\": $fa-var-creative-commons-remix,\n \"cc-amazon-pay\": $fa-var-cc-amazon-pay,\n \"dropbox\": $fa-var-dropbox,\n \"instagram\": $fa-var-instagram,\n \"cmplid\": $fa-var-cmplid,\n \"upwork\": $fa-var-upwork,\n \"facebook\": $fa-var-facebook,\n \"gripfire\": $fa-var-gripfire,\n \"jedi-order\": $fa-var-jedi-order,\n \"uikit\": $fa-var-uikit,\n \"fort-awesome-alt\": $fa-var-fort-awesome-alt,\n \"phabricator\": $fa-var-phabricator,\n \"ussunnah\": $fa-var-ussunnah,\n \"earlybirds\": $fa-var-earlybirds,\n \"trade-federation\": $fa-var-trade-federation,\n \"autoprefixer\": $fa-var-autoprefixer,\n \"whatsapp\": $fa-var-whatsapp,\n \"square-upwork\": $fa-var-square-upwork,\n \"slideshare\": $fa-var-slideshare,\n \"google-play\": $fa-var-google-play,\n \"viadeo\": $fa-var-viadeo,\n \"line\": $fa-var-line,\n \"google-drive\": $fa-var-google-drive,\n \"servicestack\": $fa-var-servicestack,\n \"simplybuilt\": $fa-var-simplybuilt,\n \"bitbucket\": $fa-var-bitbucket,\n \"imdb\": $fa-var-imdb,\n \"deezer\": $fa-var-deezer,\n \"raspberry-pi\": $fa-var-raspberry-pi,\n \"jira\": $fa-var-jira,\n \"docker\": $fa-var-docker,\n \"screenpal\": $fa-var-screenpal,\n \"bluetooth\": $fa-var-bluetooth,\n \"gitter\": $fa-var-gitter,\n \"d-and-d\": $fa-var-d-and-d,\n \"microblog\": $fa-var-microblog,\n \"cc-diners-club\": $fa-var-cc-diners-club,\n \"gg-circle\": $fa-var-gg-circle,\n \"pied-piper-hat\": $fa-var-pied-piper-hat,\n \"kickstarter-k\": $fa-var-kickstarter-k,\n \"yandex\": $fa-var-yandex,\n \"readme\": $fa-var-readme,\n \"html5\": $fa-var-html5,\n \"sellsy\": $fa-var-sellsy,\n \"square-web-awesome\": $fa-var-square-web-awesome,\n \"sass\": $fa-var-sass,\n \"wirsindhandwerk\": $fa-var-wirsindhandwerk,\n \"wsh\": $fa-var-wsh,\n \"buromobelexperte\": $fa-var-buromobelexperte,\n \"salesforce\": $fa-var-salesforce,\n \"octopus-deploy\": $fa-var-octopus-deploy,\n \"medapps\": $fa-var-medapps,\n \"ns8\": $fa-var-ns8,\n \"pinterest-p\": $fa-var-pinterest-p,\n \"apper\": $fa-var-apper,\n \"fort-awesome\": $fa-var-fort-awesome,\n \"waze\": $fa-var-waze,\n \"bluesky\": $fa-var-bluesky,\n \"cc-jcb\": $fa-var-cc-jcb,\n \"snapchat\": $fa-var-snapchat,\n \"snapchat-ghost\": $fa-var-snapchat-ghost,\n \"fantasy-flight-games\": $fa-var-fantasy-flight-games,\n \"rust\": $fa-var-rust,\n \"wix\": $fa-var-wix,\n \"square-behance\": $fa-var-square-behance,\n \"behance-square\": $fa-var-behance-square,\n \"supple\": $fa-var-supple,\n \"webflow\": $fa-var-webflow,\n \"rebel\": $fa-var-rebel,\n \"css3\": $fa-var-css3,\n \"staylinked\": $fa-var-staylinked,\n \"kaggle\": $fa-var-kaggle,\n \"space-awesome\": $fa-var-space-awesome,\n \"deviantart\": $fa-var-deviantart,\n \"cpanel\": $fa-var-cpanel,\n \"goodreads-g\": $fa-var-goodreads-g,\n \"square-git\": $fa-var-square-git,\n \"git-square\": $fa-var-git-square,\n \"square-tumblr\": $fa-var-square-tumblr,\n \"tumblr-square\": $fa-var-tumblr-square,\n \"trello\": $fa-var-trello,\n \"creative-commons-nc-jp\": $fa-var-creative-commons-nc-jp,\n \"get-pocket\": $fa-var-get-pocket,\n \"perbyte\": $fa-var-perbyte,\n \"grunt\": $fa-var-grunt,\n \"weebly\": $fa-var-weebly,\n \"connectdevelop\": $fa-var-connectdevelop,\n \"leanpub\": $fa-var-leanpub,\n \"black-tie\": $fa-var-black-tie,\n \"themeco\": $fa-var-themeco,\n \"python\": $fa-var-python,\n \"android\": $fa-var-android,\n \"bots\": $fa-var-bots,\n \"free-code-camp\": $fa-var-free-code-camp,\n \"hornbill\": $fa-var-hornbill,\n \"js\": $fa-var-js,\n \"ideal\": $fa-var-ideal,\n \"git\": $fa-var-git,\n \"dev\": $fa-var-dev,\n \"sketch\": $fa-var-sketch,\n \"yandex-international\": $fa-var-yandex-international,\n \"cc-amex\": $fa-var-cc-amex,\n \"uber\": $fa-var-uber,\n \"github\": $fa-var-github,\n \"php\": $fa-var-php,\n \"alipay\": $fa-var-alipay,\n \"youtube\": $fa-var-youtube,\n \"skyatlas\": $fa-var-skyatlas,\n \"firefox-browser\": $fa-var-firefox-browser,\n \"replyd\": $fa-var-replyd,\n \"suse\": $fa-var-suse,\n \"jenkins\": $fa-var-jenkins,\n \"twitter\": $fa-var-twitter,\n \"rockrms\": $fa-var-rockrms,\n \"pinterest\": $fa-var-pinterest,\n \"buffer\": $fa-var-buffer,\n \"npm\": $fa-var-npm,\n \"yammer\": $fa-var-yammer,\n \"btc\": $fa-var-btc,\n \"dribbble\": $fa-var-dribbble,\n \"stumbleupon-circle\": $fa-var-stumbleupon-circle,\n \"internet-explorer\": $fa-var-internet-explorer,\n \"stubber\": $fa-var-stubber,\n \"telegram\": $fa-var-telegram,\n \"telegram-plane\": $fa-var-telegram-plane,\n \"old-republic\": $fa-var-old-republic,\n \"odysee\": $fa-var-odysee,\n \"square-whatsapp\": $fa-var-square-whatsapp,\n \"whatsapp-square\": $fa-var-whatsapp-square,\n \"node-js\": $fa-var-node-js,\n \"edge-legacy\": $fa-var-edge-legacy,\n \"slack\": $fa-var-slack,\n \"slack-hash\": $fa-var-slack-hash,\n \"medrt\": $fa-var-medrt,\n \"usb\": $fa-var-usb,\n \"tumblr\": $fa-var-tumblr,\n \"vaadin\": $fa-var-vaadin,\n \"quora\": $fa-var-quora,\n \"square-x-twitter\": $fa-var-square-x-twitter,\n \"reacteurope\": $fa-var-reacteurope,\n \"medium\": $fa-var-medium,\n \"medium-m\": $fa-var-medium-m,\n \"amilia\": $fa-var-amilia,\n \"mixcloud\": $fa-var-mixcloud,\n \"flipboard\": $fa-var-flipboard,\n \"viacoin\": $fa-var-viacoin,\n \"critical-role\": $fa-var-critical-role,\n \"sitrox\": $fa-var-sitrox,\n \"discourse\": $fa-var-discourse,\n \"joomla\": $fa-var-joomla,\n \"mastodon\": $fa-var-mastodon,\n \"airbnb\": $fa-var-airbnb,\n \"wolf-pack-battalion\": $fa-var-wolf-pack-battalion,\n \"buy-n-large\": $fa-var-buy-n-large,\n \"gulp\": $fa-var-gulp,\n \"creative-commons-sampling-plus\": $fa-var-creative-commons-sampling-plus,\n \"strava\": $fa-var-strava,\n \"ember\": $fa-var-ember,\n \"canadian-maple-leaf\": $fa-var-canadian-maple-leaf,\n \"teamspeak\": $fa-var-teamspeak,\n \"pushed\": $fa-var-pushed,\n \"wordpress-simple\": $fa-var-wordpress-simple,\n \"nutritionix\": $fa-var-nutritionix,\n \"wodu\": $fa-var-wodu,\n \"google-pay\": $fa-var-google-pay,\n \"intercom\": $fa-var-intercom,\n \"zhihu\": $fa-var-zhihu,\n \"korvue\": $fa-var-korvue,\n \"pix\": $fa-var-pix,\n \"steam-symbol\": $fa-var-steam-symbol,\n);\n", + ".#{$fa-css-prefix}.#{$fa-css-prefix}-glass { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-martini-glass-empty }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-envelope-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-envelope-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-envelope }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-star-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-star-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-star }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-remove { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-xmark }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-close { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-xmark }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-gear { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-gear }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-trash-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-trash-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-trash-can }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-home { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-house }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-file }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-clock-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-clock-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-clock }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-down {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-down { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-circle-down }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-up {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-up { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-circle-up }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-play-circle-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-play-circle-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-circle-play }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-repeat { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-arrow-rotate-right }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-rotate-right { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-arrow-rotate-right }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-refresh { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-arrows-rotate }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-list-alt {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-list-alt { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-rectangle-list }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-dedent { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-outdent }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-video-camera { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-video }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-picture-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-picture-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-image }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-photo {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-photo { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-image }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-image {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-image { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-image }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-map-marker { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-location-dot }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-pencil-square-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-pencil-square-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-pen-to-square }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-edit {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-edit { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-pen-to-square }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-share-square-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-share-from-square }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-check-square-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-check-square-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-check }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-arrows { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-up-down-left-right }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-times-circle-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-times-circle-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-circle-xmark }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-check-circle-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-check-circle-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-circle-check }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-mail-forward { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-share }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-expand { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-up-right-and-down-left-from-center }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-compress { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-down-left-and-up-right-to-center }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-eye {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-eye-slash {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-warning { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-triangle-exclamation }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-calendar-days }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-arrows-v { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-up-down }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-arrows-h { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-left-right }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-bar-chart { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-chart-column }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-bar-chart-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-chart-column }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-twitter-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-twitter-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-twitter }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-facebook }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-gears { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-gears }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-thumbs-o-up {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-thumbs-o-up { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-thumbs-up }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-thumbs-o-down {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-thumbs-o-down { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-thumbs-down }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-heart-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-heart-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-heart }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-sign-out { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-right-from-bracket }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-linkedin-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-linkedin-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-linkedin }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-thumb-tack { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-thumbtack }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-external-link { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-up-right-from-square }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-sign-in { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-right-to-bracket }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-github-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-github-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-github }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-lemon-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-lemon-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-lemon }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-square-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-square-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-bookmark-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-bookmark-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-bookmark }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-twitter {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-facebook-f }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook-f {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook-f { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-facebook-f }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-github {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-credit-card {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-feed { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-rss }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hdd-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hdd-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hard-drive }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-right {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-right { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hand-point-right }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-left {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-left { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hand-point-left }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-up {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-up { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hand-point-up }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-down {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-down { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hand-point-down }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-globe { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-earth-americas }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-tasks { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-bars-progress }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-arrows-alt { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-maximize }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-group { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-users }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-chain { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-link }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-cut { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-scissors }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-files-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-files-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-copy }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-floppy-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-floppy-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-floppy-disk }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-save {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-save { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-floppy-disk }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-navicon { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-bars }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-reorder { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-bars }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-magic { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-wand-magic-sparkles }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-pinterest {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-pinterest-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-pinterest-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-pinterest }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-google-plus }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-google-plus-g }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-money { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-money-bill-1 }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-unsorted { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-sort }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-desc { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-sort-down }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-asc { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-sort-up }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-linkedin {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-linkedin { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-linkedin-in }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-rotate-left { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-arrow-rotate-left }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-legal { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-gavel }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-tachometer { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-gauge-high }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-dashboard { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-gauge-high }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-comment-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-comment-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-comment }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-comments-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-comments-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-comments }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-flash { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-bolt }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-clipboard { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-paste }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-lightbulb-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-lightbulb-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-lightbulb }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-exchange { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-right-left }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-cloud-download { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-cloud-arrow-down }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-cloud-upload { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-cloud-arrow-up }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-bell-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-bell-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-bell }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-cutlery { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-utensils }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-text-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-text-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-file-lines }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-building-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-building-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-building }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hospital-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hospital-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hospital }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-tablet { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-tablet-screen-button }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-mobile { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-mobile-screen-button }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-mobile-phone { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-mobile-screen-button }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-circle-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-circle-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-circle }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-mail-reply { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-reply }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-github-alt {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-folder-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-folder-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-folder }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-folder-open-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-folder-open-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-folder-open }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-smile-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-smile-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-face-smile }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-frown-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-frown-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-face-frown }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-meh-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-meh-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-face-meh }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-keyboard-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-keyboard-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-keyboard }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-flag-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-flag-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-flag }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-mail-reply-all { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-reply-all }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-star-half-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-star-half-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-star-half-stroke }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-star-half-empty {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-star-half-empty { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-star-half-stroke }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-star-half-full {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-star-half-full { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-star-half-stroke }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-code-fork { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-code-branch }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-chain-broken { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-link-slash }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-unlink { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-link-slash }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-calendar }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-maxcdn {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-html5 {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-css3 {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-unlock-alt { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-unlock }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-minus-square-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-minus-square-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-minus }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-level-up { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-turn-up }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-level-down { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-turn-down }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-pencil-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-pen }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-external-link-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-up-right }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-compass {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-down {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-down { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-caret-down }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-down {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-down { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-caret-down }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-up {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-up { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-caret-up }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-up {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-up { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-caret-up }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-right {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-right { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-caret-right }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-right {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-right { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-caret-right }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-eur { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-euro-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-euro { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-euro-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-gbp { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-sterling-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-usd { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-dollar-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-dollar { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-dollar-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-inr { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-indian-rupee-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-rupee { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-indian-rupee-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-jpy { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-yen-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-cny { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-yen-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-rmb { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-yen-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-yen { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-yen-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-rub { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-ruble-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-ruble { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-ruble-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-rouble { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-ruble-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-krw { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-won-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-won { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-won-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-btc {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-bitcoin {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-bitcoin { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-btc }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-text { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-file-lines }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-alpha-asc { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-arrow-down-a-z }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-alpha-desc { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-arrow-down-z-a }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-amount-asc { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-arrow-down-short-wide }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-amount-desc { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-arrow-down-wide-short }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-numeric-asc { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-arrow-down-1-9 }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-numeric-desc { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-arrow-down-9-1 }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-youtube-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-youtube-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-youtube }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-youtube {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-xing {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-xing-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-xing-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-xing }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-youtube-play {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-youtube-play { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-youtube }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-dropbox {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-stack-overflow {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-instagram {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-flickr {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-adn {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-bitbucket {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-bitbucket-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-bitbucket-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-bitbucket }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-tumblr {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-tumblr-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-tumblr-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-tumblr }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-long-arrow-down { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-down-long }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-long-arrow-up { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-up-long }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-long-arrow-left { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-left-long }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-long-arrow-right { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-right-long }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-apple {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-windows {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-android {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-linux {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-dribbble {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-skype {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-foursquare {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-trello {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-gratipay {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-gittip {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-gittip { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-gratipay }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-sun-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-sun-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-sun }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-moon-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-moon-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-moon }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-vk {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-weibo {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-renren {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-pagelines {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-stack-exchange {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-right {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-right { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-circle-right }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-left {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-left { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-circle-left }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-left {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-left { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-caret-left }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-left {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-left { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-caret-left }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-dot-circle-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-dot-circle-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-circle-dot }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-vimeo-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-vimeo-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-vimeo }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-try { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-turkish-lira-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-turkish-lira { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-turkish-lira-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-plus-square-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-plus-square-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-plus }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-slack {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-wordpress {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-openid {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-institution { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-building-columns }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-bank { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-building-columns }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-mortar-board { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-graduation-cap }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-yahoo {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-google {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-reddit {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-reddit-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-reddit-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-reddit }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-stumbleupon-circle {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-stumbleupon {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-delicious {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-digg {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-pied-piper-pp {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-pied-piper-alt {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-drupal {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-joomla {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-behance {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-behance-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-behance-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-behance }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-steam {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-steam-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-steam-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-steam }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-automobile { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-car }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-cab { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-taxi }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-spotify {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-deviantart {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-soundcloud {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-pdf-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-pdf-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-file-pdf }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-word-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-word-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-file-word }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-excel-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-excel-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-file-excel }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-powerpoint-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-powerpoint-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-file-powerpoint }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-image-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-image-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-file-image }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-photo-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-photo-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-file-image }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-picture-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-picture-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-file-image }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-archive-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-archive-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-file-zipper }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-zip-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-zip-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-file-zipper }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-audio-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-audio-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-file-audio }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-sound-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-sound-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-file-audio }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-video-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-video-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-file-video }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-movie-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-movie-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-file-video }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-code-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-file-code-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-file-code }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-vine {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-codepen {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-jsfiddle {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-life-bouy { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-life-ring }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-life-buoy { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-life-ring }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-life-saver { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-life-ring }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-support { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-life-ring }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-circle-o-notch { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-circle-notch }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-rebel {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-ra {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-ra { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-rebel }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-resistance {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-resistance { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-rebel }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-empire {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-ge {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-ge { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-empire }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-git-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-git-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-git }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-git {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hacker-news {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-y-combinator-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-y-combinator-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hacker-news }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-yc-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-yc-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hacker-news }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-tencent-weibo {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-qq {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-weixin {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-wechat {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-wechat { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-weixin }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-send { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-paper-plane }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-paper-plane-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-paper-plane-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-paper-plane }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-send-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-send-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-paper-plane }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-circle-thin {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-circle-thin { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-circle }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-header { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-heading }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-futbol-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-futbol-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-futbol }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-soccer-ball-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-soccer-ball-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-futbol }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-slideshare {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-twitch {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-yelp {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-newspaper-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-newspaper-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-newspaper }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-paypal {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-google-wallet {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-visa {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-mastercard {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-discover {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-amex {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-paypal {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-stripe {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-bell-slash-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-bell-slash-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-bell-slash }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-trash { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-trash-can }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-copyright {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-eyedropper { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-eye-dropper }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-area-chart { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-chart-area }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-pie-chart { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-chart-pie }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-line-chart { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-chart-line }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-lastfm {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-lastfm-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-lastfm-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-lastfm }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-ioxhost {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-angellist {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-cc {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-cc { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-closed-captioning }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-ils { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-shekel-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-shekel { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-shekel-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-sheqel { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-shekel-sign }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-buysellads {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-connectdevelop {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-dashcube {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-forumbee {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-leanpub {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-sellsy {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-shirtsinbulk {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-simplybuilt {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-skyatlas {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-diamond {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-diamond { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-gem }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-transgender { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-mars-and-venus }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-intersex { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-mars-and-venus }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-transgender-alt { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-transgender }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook-official {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook-official { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-facebook }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-pinterest-p {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-whatsapp {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hotel { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-bed }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-viacoin {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-medium {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-y-combinator {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-yc {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-yc { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-y-combinator }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-optin-monster {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-opencart {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-expeditedssl {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-battery-4 { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-battery-full }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-battery { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-battery-full }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-battery-3 { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-battery-three-quarters }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-battery-2 { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-battery-half }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-battery-1 { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-battery-quarter }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-battery-0 { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-battery-empty }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-object-group {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-object-ungroup {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-sticky-note-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-sticky-note-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-note-sticky }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-jcb {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-diners-club {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-clone {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hourglass-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hourglass }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hourglass-1 { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hourglass-start }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hourglass-2 { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hourglass-half }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hourglass-3 { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hourglass-end }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-rock-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-rock-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hand-back-fist }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-grab-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-grab-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hand-back-fist }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-paper-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-paper-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hand }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-stop-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-stop-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hand }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-scissors-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-scissors-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hand-scissors }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-lizard-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-lizard-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hand-lizard }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-spock-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-spock-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hand-spock }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-pointer-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-pointer-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hand-pointer }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-peace-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-peace-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hand-peace }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-registered {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-creative-commons {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-gg {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-gg-circle {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-odnoklassniki {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-odnoklassniki-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-odnoklassniki-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-odnoklassniki }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-get-pocket {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-wikipedia-w {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-safari {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-chrome {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-firefox {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-opera {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-internet-explorer {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-television { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-tv }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-contao {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-500px {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-amazon {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-plus-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-plus-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-calendar-plus }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-minus-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-minus-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-calendar-minus }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-times-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-times-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-calendar-xmark }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-check-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-check-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-calendar-check }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-map-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-map-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-map }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-commenting { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-comment-dots }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-commenting-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-commenting-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-comment-dots }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-houzz {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-vimeo {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-vimeo { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-vimeo-v }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-black-tie {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-fonticons {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-reddit-alien {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-edge {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-credit-card-alt { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-credit-card }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-codiepie {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-modx {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-fort-awesome {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-usb {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-product-hunt {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-mixcloud {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-scribd {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-pause-circle-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-pause-circle-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-circle-pause }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-stop-circle-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-stop-circle-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-circle-stop }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-bluetooth {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-bluetooth-b {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-gitlab {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-wpbeginner {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-wpforms {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-envira {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-wheelchair-alt {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-wheelchair-alt { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-accessible-icon }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-question-circle-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-question-circle-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-circle-question }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-volume-control-phone { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-phone-volume }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-asl-interpreting { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hands-asl-interpreting }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-deafness { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-ear-deaf }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-hard-of-hearing { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-ear-deaf }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-glide {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-glide-g {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-signing { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-hands }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-viadeo {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-viadeo-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-viadeo-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-viadeo }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-snapchat {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-snapchat-ghost {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-snapchat-ghost { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-snapchat }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-snapchat-square {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-snapchat-square { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-square-snapchat }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-pied-piper {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-first-order {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-yoast {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-themeisle {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus-official {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus-official { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-google-plus }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus-circle {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus-circle { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-google-plus }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-font-awesome {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-fa {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-fa { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-font-awesome }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-handshake-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-handshake-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-handshake }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-envelope-open-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-envelope-open-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-envelope-open }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-linode {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-address-book-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-address-book-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-address-book }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-vcard { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-address-card }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-address-card-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-address-card-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-address-card }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-vcard-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-vcard-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-address-card }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-user-circle-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-user-circle-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-circle-user }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-user-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-user-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-user }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-id-badge {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-drivers-license { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-id-card }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-id-card-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-id-card-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-id-card }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-drivers-license-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-drivers-license-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-id-card }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-quora {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-free-code-camp {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-telegram {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-thermometer-4 { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-temperature-full }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-thermometer { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-temperature-full }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-thermometer-3 { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-temperature-three-quarters }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-thermometer-2 { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-temperature-half }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-thermometer-1 { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-temperature-quarter }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-thermometer-0 { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-temperature-empty }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-bathtub { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-bath }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-s15 { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-bath }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-window-maximize {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-window-restore {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-times-rectangle { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-rectangle-xmark }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-window-close-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-window-close-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-rectangle-xmark }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-times-rectangle-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-times-rectangle-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-rectangle-xmark }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-bandcamp {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-grav {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-etsy {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-imdb {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-ravelry {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-eercast {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-eercast { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-sellcast }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-snowflake-o {\n font-family: 'Font Awesome 6 Free';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-snowflake-o { #{$fa-icon-property}: unquote(\"\\\"#{ $fa-var-snowflake }\\\"\"); }\n.#{$fa-css-prefix}.#{$fa-css-prefix}-superpowers {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-wpexplorer {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n.#{$fa-css-prefix}.#{$fa-css-prefix}-meetup {\n font-family: 'Font Awesome 6 Brands';\n font-weight: 400;\n}\n", + "*,\n*:after,\n*:before {\n box-sizing: inherit;\n}\n\nhtml {\n box-sizing: border-box;\n font-size: 62.5%;\n}\n\nbody {\n color: $fg-color;\n background-color: $bg-color;\n font-family: $font-family;\n font-size: 1.8em;\n font-weight: 400;\n line-height: 1.8em;\n\n @media only screen and (max-width: 768px) {\n font-size: 1.6em;\n line-height: 1.6em;\n }\n}\n\niframe[src*=disqus] {\n color-scheme: light;\n}\n\na {\n font-weight: 500;\n color: $link-color;\n text-decoration: none;\n transition: all 0.25s ease-in;\n\n &:focus,\n &:hover {\n text-decoration: underline;\n }\n}\n\np {\n margin: 2rem 0 2rem 0;\n white-space: pre-wrap;\n white-space: -moz-pre-wrap;\n white-space: -pre-wrap;\n white-space: -o-pre-wrap;\n word-wrap: break-word;\n @media only screen and (max-width: 768px) {\n margin: 1.5rem 0 1.5rem 0;\n }\n}\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n font-family: $font-family;\n font-weight: 600;\n color: $alt-fg-color;\n margin: 4rem 0 2.5rem 0;\n\n &:hover .heading-link {\n visibility: visible;\n }\n\n .heading-link {\n color: $link-color;\n font-weight: inherit;\n text-decoration: none;\n font-size: 80%;\n visibility: hidden;\n }\n\n .title-link {\n color: inherit;\n font-weight: inherit;\n text-decoration: none;\n }\n}\n\nh1 {\n font-size: 3.2rem;\n line-height: 3.6rem;\n\n @media only screen and (max-width: 768px) {\n font-size: 3rem;\n line-height: 3.4rem;\n }\n}\n\nh2 {\n font-size: 2.8rem;\n line-height: 3.2rem;\n\n @media only screen and (max-width: 768px) {\n font-size: 2.6rem;\n line-height: 3rem;\n }\n}\n\nh3 {\n font-size: 2.4rem;\n line-height: 2.8rem;\n\n @media only screen and (max-width: 768px) {\n font-size: 2.2rem;\n line-height: 2.6rem;\n }\n}\n\nh4 {\n font-size: 2.2rem;\n line-height: 2.6rem;\n\n @media only screen and (max-width: 768px) {\n font-size: 2rem;\n line-height: 2.4rem;\n }\n}\n\nh5 {\n font-size: 2rem;\n line-height: 2.4rem;\n\n @media only screen and (max-width: 768px) {\n font-size: 1.8rem;\n line-height: 2.2rem;\n }\n}\n\nh6 {\n font-size: 1.8rem;\n line-height: 2.2rem;\n\n @media only screen and (max-width: 768px) {\n font-size: 1.6rem;\n line-height: 2rem;\n }\n}\n\nb,\nstrong {\n font-weight: 700;\n}\n\n.highlight {\n\n div,\n pre {\n margin: 2rem 0 2rem;\n padding: 1rem;\n border-radius: 1rem;\n overflow-x: auto;\n }\n}\n\npre {\n display: block;\n font-family: $code-font-family;\n font-size: 1.6rem;\n font-weight: 400;\n line-height: 2.6rem;\n overflow-x: auto;\n margin: 2rem 0 2rem;\n padding: 1rem;\n border-radius: 1rem;\n\n code {\n display: inline-block;\n background-color: inherit;\n color: inherit;\n }\n}\n\ncode {\n font-family: $code-font-family;\n font-size: 1.6rem;\n font-weight: 400;\n border-radius: 0.6rem;\n padding: 0.3rem 0.6rem;\n background-color: $darker-alt-bg-color;\n color: $fg-color;\n @media only screen and (max-width: 768px) {\n font-size: 1.5rem;\n }\n}\n\nblockquote {\n border-left: 2px solid $alt-bg-color;\n padding-left: 2rem;\n line-height: 2.2rem;\n font-weight: 400;\n font-style: italic;\n}\n\nth,\ntd {\n padding: 1.6rem;\n}\n\ntable {\n border-collapse: collapse;\n}\n\ntable td,\ntable th {\n border: 2px solid $alt-fg-color;\n}\n\ntable tr:first-child th {\n border-top: 0;\n}\n\ntable tr:last-child td {\n border-bottom: 0;\n}\n\ntable tr td:first-child,\ntable tr th:first-child {\n border-left: 0;\n}\n\ntable tr td:last-child,\ntable tr th:last-child {\n border-right: 0;\n}\n\nimg {\n max-width: 100%;\n}\n\nfigure {\n text-align: center;\n}\n\n.footnotes {\n ol li p {\n margin: 0;\n }\n}\n\n.preload-transitions * {\n $null-transition: none !important;\n\n -webkit-transition: $null-transition;\n -moz-transition: $null-transition;\n -ms-transition: $null-transition;\n -o-transition: $null-transition;\n transition: $null-transition;\n}\n\n.wrapper {\n display: flex;\n flex-direction: column;\n\n min-height: 100vh;\n width: 100%;\n}\n\n.container {\n margin: 1rem auto;\n max-width: 90rem;\n width: 100%;\n padding-left: 2rem;\n padding-right: 2rem;\n}\n\n.fab {\n font-weight: 400;\n}\n\n.fas {\n font-weight: 700;\n}\n\n.float-right {\n float: right;\n}\n\n.float-left {\n float: left;\n}\n\n.fab {\n font-weight: 400;\n}\n\n.fas {\n font-weight: 900;\n}\n", + ".content {\n flex: 1;\n display: flex;\n margin-top: 1.6rem;\n margin-bottom: 3.2rem;\n @media only screen and (max-width: 768px) {\n margin-top: 1rem;\n margin-bottom: 1.6rem;\n }\n\n header {\n margin-top: 6.4rem;\n margin-bottom: 3.2rem;\n\n h1 {\n font-size: 4.2rem;\n line-height: 4.6rem;\n margin: 0;\n\n @media only screen and (max-width: 768px) {\n font-size: 4rem;\n line-height: 4.4rem;\n }\n }\n }\n\n article {\n a:where(.external-link):not(:has(img)):after {\n @extend %fa-icon;\n @extend .fa-solid;\n content: fa-content($fa-var-external-link);\n padding-left: 0.5em;\n font-size: 0.75em;\n }\n\n details {\n summary {\n cursor: pointer;\n }\n }\n\n footer {\n margin-top: 4rem;\n\n .see-also {\n margin: 3.2rem 0;\n\n h3 {\n margin: 3.2rem 0;\n }\n }\n }\n\n p {\n text-align: justify;\n text-justify: auto;\n -ms-hyphens: auto;\n -webkit-hyphens: auto;\n hyphens: auto;\n }\n }\n\n .post {\n .post-title {\n margin-bottom: 0.75em;\n }\n\n .post-meta {\n i {\n text-align: center;\n width: 1.6rem;\n margin-left: 0;\n margin-right: 0.5rem;\n }\n\n .date {\n .posted-on {\n margin-left: 0;\n margin-right: 1.5rem;\n }\n }\n\n .tags {\n .tag {\n display: inline-block;\n padding: 0.3rem 0.6rem;\n background-color: $alt-bg-color;\n border-radius: 0.6rem;\n line-height: 1.5em;\n\n a {\n color: $fg-color;\n }\n\n a:active {\n color: $fg-color;\n }\n }\n }\n }\n }\n\n figure {\n margin: 0;\n padding: 0;\n }\n\n figcaption p {\n text-align: center;\n font-style: italic;\n font-size: 1.6rem;\n margin: 0;\n }\n}\n\n.avatar img {\n width: 20rem;\n height: auto;\n border-radius: 50%;\n\n @media only screen and (max-width: 768px) {\n width: 17rem;\n }\n}\n\n.list {\n ul {\n margin: 3.2rem 0 3.2rem 0;\n list-style: none;\n padding: 0;\n\n li {\n font-size: 1.8rem;\n\n @media only screen and (max-width: 768px) {\n margin: 1.6rem 0 1.6rem 0;\n }\n\n .date {\n display: inline-block;\n flex: 1;\n width: 20rem;\n text-align: right;\n margin-right: 3rem;\n\n @media only screen and (max-width: 768px) {\n display: block;\n text-align: left;\n }\n }\n\n .title {\n font-size: 1.8rem;\n flex: 2;\n color: $fg-color;\n font-family: $font-family;\n font-weight: 700;\n\n &:hover,\n &:focus {\n color: $link-color;\n }\n }\n }\n }\n\n ul:not(.pagination) {\n li {\n @media only screen and (min-width: 768.1px) {\n display: flex;\n }\n }\n }\n}\n\n.centered {\n display: flex;\n align-items: center;\n justify-content: center;\n\n .about {\n text-align: center;\n\n h1 {\n margin-top: 2rem;\n margin-bottom: 0.5rem;\n }\n\n h2 {\n margin-top: 1rem;\n margin-bottom: 0.5rem;\n font-size: 2.4rem;\n\n @media only screen and (max-width: 768px) {\n font-size: 2rem;\n }\n }\n\n ul {\n list-style: none;\n margin: 3rem 0 1rem 0;\n padding: 0;\n cursor: pointer;\n\n li {\n display: inline-block;\n position: relative;\n\n a {\n color: $fg-color;\n text-transform: uppercase;\n margin-left: 1rem;\n margin-right: 1rem;\n font-size: 1.6rem;\n\n &:hover,\n &:focus {\n color: $link-color;\n }\n\n @media only screen and (max-width: 768px) {\n font-size: 1.5rem;\n }\n }\n }\n }\n }\n\n .error {\n text-align: center;\n\n h1 {\n margin-top: 2rem;\n margin-bottom: 0.5rem;\n font-size: 4.6rem;\n\n @media only screen and (max-width: 768px) {\n font-size: 3.2rem;\n }\n }\n\n h2 {\n margin-top: 2rem;\n margin-bottom: 3.2rem;\n font-size: 3.2rem;\n\n @media only screen and (max-width: 768px) {\n font-size: 2.8rem;\n }\n }\n }\n}\n", + ".notice {\n border-radius: 0.2rem;\n position: relative;\n margin: 2rem 0;\n padding: 0 0.75rem;\n overflow: auto;\n\n .notice-title {\n position: relative;\n font-weight: 700;\n margin: 0 -0.75rem;\n padding: 0.2rem 3.5rem;\n border-bottom: 1px solid $bg-color;\n\n i {\n position: absolute;\n top: 50%;\n left: 1.8rem;\n transform: translate(-50%, -50%);\n }\n }\n\n .notice-content {\n display: block;\n margin: 2rem 2rem;\n }\n}\n\n.notice.note {\n background-color: $bg-color-notice-note-content;\n\n .notice-title {\n background-color: $bg-color-notice-note-title;\n\n i {\n color: $fg-color-notice-note-icon;\n }\n }\n}\n\n.notice.tip {\n background-color: $bg-color-notice-tip-content;\n\n .notice-title {\n background-color: $bg-color-notice-tip-title;\n\n i {\n color: $fg-color-notice-tip-icon;\n }\n }\n}\n\n.notice.example {\n background-color: $bg-color-notice-example-content;\n\n .notice-title {\n background-color: $bg-color-notice-example-title;\n\n i {\n color: $fg-color-notice-example-icon;\n }\n }\n}\n\n.notice.question {\n background-color: $bg-color-notice-question-content;\n\n .notice-title {\n background-color: $bg-color-notice-question-title;\n\n i {\n color: $fg-color-notice-question-icon;\n }\n }\n}\n\n.notice.info {\n background-color: $bg-color-notice-info-content;\n\n .notice-title {\n background-color: $bg-color-notice-info-title;\n\n i {\n color: $fg-color-notice-info-icon;\n }\n }\n}\n\n.notice.warning {\n background-color: $bg-color-notice-warning-content;\n\n .notice-title {\n background-color: $bg-color-notice-warning-title;\n\n i {\n color: $fg-color-notice-warning-icon;\n }\n }\n}\n\n.notice.error {\n background-color: $bg-color-notice-error-content;\n\n .notice-title {\n background-color: $bg-color-notice-error-title;\n\n i {\n color: $fg-color-notice-error-icon;\n }\n }\n}\n", + ".navigation {\n height: 6rem;\n width: 100%;\n\n a,\n span {\n display: inline;\n font-size: 1.7rem;\n font-family: $font-family;\n font-weight: 600;\n color: $fg-color;\n }\n\n a {\n\n &:hover,\n &:focus {\n color: $link-color;\n }\n }\n\n .navigation-title {\n letter-spacing: 0.1rem;\n text-transform: uppercase;\n }\n\n .navigation-list {\n float: right;\n list-style: none;\n margin-bottom: 0;\n margin-top: 0;\n\n @media only screen and (max-width: 768px) {\n position: relative;\n top: 2rem;\n right: 0;\n z-index: 5;\n visibility: hidden;\n opacity: 0;\n padding: 0;\n max-height: 0;\n width: 100%;\n background-color: $bg-color;\n border-top: solid 2px $alt-bg-color;\n border-bottom: solid 2px $alt-bg-color;\n transition: opacity 0.25s, max-height 0.15s linear;\n }\n\n .navigation-item {\n float: left;\n margin: 0;\n position: relative;\n\n @media only screen and (max-width: 768px) {\n float: none !important;\n text-align: center;\n\n a,\n span {\n line-height: 5rem;\n }\n }\n\n a,\n span {\n margin-left: 1rem;\n margin-right: 1rem;\n }\n }\n\n .separator {\n @media only screen and (max-width: 768px) {\n display: none;\n }\n }\n\n .menu-separator {\n @media only screen and (max-width: 768px) {\n border-top: 2px solid $fg-color;\n margin: 0 8rem;\n\n span {\n display: none;\n }\n }\n }\n }\n\n #dark-mode-toggle {\n margin: 1.7rem 0;\n font-size: 2.4rem;\n line-height: inherit;\n bottom: 2rem;\n left: 2rem;\n z-index: 100;\n position: fixed;\n }\n\n #menu-toggle {\n display: none;\n\n @media only screen and (max-width: 768px) {\n display: initial;\n position: relative;\n visibility: hidden;\n\n &:checked+label>i {\n color: $alt-bg-color;\n }\n\n &:checked+label+ul {\n visibility: visible;\n opacity: 1;\n max-height: 100rem;\n }\n\n &:focus-visible+label {\n outline-style: auto;\n }\n }\n }\n\n .menu-button {\n display: none;\n\n @media only screen and (max-width: 768px) {\n position: relative;\n display: block;\n font-size: 2.4rem;\n font-weight: 400;\n }\n\n i {\n\n &:hover,\n &:focus {\n color: $alt-fg-color;\n }\n }\n }\n\n i {\n color: $fg-color;\n cursor: pointer;\n\n &:hover,\n &:focus {\n color: $link-color;\n }\n }\n}\n", + ".pagination {\n display: flex;\n justify-content: center;\n\n margin-top: 6rem;\n text-align: center;\n font-family: $font-family;\n\n li {\n display: inline;\n text-align: center;\n font-weight: 700;\n padding: 0 5px 0 5px;\n\n margin: 0;\n text-align: center;\n width: 2.2rem;\n\n a {\n font-weight: 300;\n }\n }\n}\n", + ".tabs {\n display: flex;\n flex-wrap: wrap;\n margin: 2rem 0 2rem 0;\n position: relative;\n\n &.tabs-left {\n justify-content: flex-start;\n\n label.tab-label {\n margin-right: 0.5rem;\n }\n\n .tab-content {\n border-radius: 0px 4px 4px 4px;\n }\n }\n\n &.tabs-right {\n justify-content: flex-end;\n\n label.tab-label {\n margin-left: 0.5rem;\n }\n\n .tab-content {\n border-radius: 4px 0px 4px 4px;\n }\n }\n\n input.tab-input {\n display: none;\n }\n\n label.tab-label {\n background-color: $alt-bg-color;\n border-color: $darker-alt-bg-color;\n border-radius: 4px 4px 0px 0px;\n\n border-style: solid;\n border-bottom-style: hidden;\n\n border-width: 1px;\n cursor: pointer;\n display: inline-block;\n order: 1;\n padding: 0.3rem 0.6rem;\n position: relative;\n top: 1px;\n user-select: none;\n }\n\n input.tab-input:checked + label.tab-label {\n background-color: $bg-color;\n }\n\n .tab-content {\n background-color: $bg-color;\n border-color: $darker-alt-bg-color;\n border-style: solid;\n border-width: 1px;\n display: none;\n order: 2;\n padding: 1rem;\n width: 100%;\n }\n\n &.tabs-code {\n .tab-content {\n padding: 0.5rem;\n\n pre {\n margin: 0;\n }\n }\n }\n}\n", + ".taxonomy {\n li {\n display: inline-block;\n margin: 0.9rem;\n }\n\n .taxonomy-element {\n display: block;\n padding: 0.3rem 0.9rem;\n background-color: $alt-bg-color;\n border-radius: 0.6rem;\n\n a {\n color: $fg-color;\n }\n a:active {\n color: $fg-color;\n }\n }\n}\n", + ".footer {\n width: 100%;\n text-align: center;\n font-size: 1.6rem;\n line-height: 2rem;\n margin-bottom: 1rem;\n @media only screen and (max-width: 768px) {\n font-size: 1.5rem;\n }\n a {\n color: $link-color;\n }\n}\n", + ".float-container {\n bottom: 2rem;\n right: 2rem;\n z-index: 100;\n position: fixed;\n font-size: 1.6em;\n\n a {\n position: relative;\n display: inline-block;\n width: 3rem;\n height: 3rem;\n font-size: 2rem;\n color: $alt-fg-color;\n background-color: $alt-bg-color;\n border-radius: 0.2rem;\n opacity: 0.5;\n transition: all 0.25s ease-in;\n\n &:hover,\n &:focus {\n color: $link-color;\n opacity: 1;\n\n @media only screen and (max-width: 768px) {\n color: $alt-fg-color;\n opacity: 0.5;\n }\n }\n\n i {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n }\n }\n}\n", + ".mastodon-wrapper {\n display: flex;\n gap: 3rem;\n flex-direction: row;\n}\n\n.comment-level {\n max-width: 3rem;\n min-width: 3rem;\n}\n\n.reply-original {\n display: none;\n}\n\n.mastodon-comment {\n background-color: var(--body-background);\n border-radius: var(--card-border-radius);\n padding: var(--card-padding);\n margin-bottom: 1rem;\n display: flex;\n gap: 1rem;\n flex-direction: column;\n flex-grow: 2;\n\n .comment {\n display: flex;\n flex-direction: row;\n gap: 1rem;\n flex-wrap: true;\n }\n\n .comment-avatar img {\n width: 6rem;\n }\n\n .content {\n flex-grow: 2;\n }\n\n .comment-author {\n display: flex;\n flex-direction: column;\n\n &-name {\n font-weight: bold;\n a {\n display: flex;\n align-items: center;\n }\n }\n\n &-date {\n margin-left: auto;\n }\n }\n\n .disabled {\n color: var(--accent-color)\n }\n}\n\n.mastodon-comment-content p:first-child {\n margin-top: 0;\n}\n\n.mastodon {\n --dlg-bg: #282c37;\n --dlg-w: 600px;\n --dlg-color: #9baec8;\n --dlg-button-p: 0.75em 2em;\n --dlg-outline-c: #00D9F5;\n}\n", + "/* Background */ .bg { background-color: #ffffff; }\n/* PreWrapper */ .chroma { background-color: #ffffff; }\n/* Other */ .chroma .x { }\n/* Error */ .chroma .err { color: #a61717; background-color: #e3d2d2 }\n/* CodeLine */ .chroma .cl { }\n/* LineLink */ .chroma .lnlinks { outline: none; text-decoration: none; color: inherit }\n/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }\n/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; }\n/* LineHighlight */ .chroma .hl { background-color: #ffffcc }\n/* LineNumbersTable */ .chroma .lnt { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }\n/* LineNumbers */ .chroma .ln { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }\n/* Line */ .chroma .line { display: flex; }\n/* Keyword */ .chroma .k { color: #000000; font-weight: bold }\n/* KeywordConstant */ .chroma .kc { color: #000000; font-weight: bold }\n/* KeywordDeclaration */ .chroma .kd { color: #000000; font-weight: bold }\n/* KeywordNamespace */ .chroma .kn { color: #000000; font-weight: bold }\n/* KeywordPseudo */ .chroma .kp { color: #000000; font-weight: bold }\n/* KeywordReserved */ .chroma .kr { color: #000000; font-weight: bold }\n/* KeywordType */ .chroma .kt { color: #445588; font-weight: bold }\n/* Name */ .chroma .n { }\n/* NameAttribute */ .chroma .na { color: #008080 }\n/* NameBuiltin */ .chroma .nb { color: #0086b3 }\n/* NameBuiltinPseudo */ .chroma .bp { color: #999999 }\n/* NameClass */ .chroma .nc { color: #445588; font-weight: bold }\n/* NameConstant */ .chroma .no { color: #008080 }\n/* NameDecorator */ .chroma .nd { color: #3c5d5d; font-weight: bold }\n/* NameEntity */ .chroma .ni { color: #800080 }\n/* NameException */ .chroma .ne { color: #990000; font-weight: bold }\n/* NameFunction */ .chroma .nf { color: #990000; font-weight: bold }\n/* NameFunctionMagic */ .chroma .fm { }\n/* NameLabel */ .chroma .nl { color: #990000; font-weight: bold }\n/* NameNamespace */ .chroma .nn { color: #555555 }\n/* NameOther */ .chroma .nx { }\n/* NameProperty */ .chroma .py { }\n/* NameTag */ .chroma .nt { color: #000080 }\n/* NameVariable */ .chroma .nv { color: #008080 }\n/* NameVariableClass */ .chroma .vc { color: #008080 }\n/* NameVariableGlobal */ .chroma .vg { color: #008080 }\n/* NameVariableInstance */ .chroma .vi { color: #008080 }\n/* NameVariableMagic */ .chroma .vm { }\n/* Literal */ .chroma .l { }\n/* LiteralDate */ .chroma .ld { }\n/* LiteralString */ .chroma .s { color: #dd1144 }\n/* LiteralStringAffix */ .chroma .sa { color: #dd1144 }\n/* LiteralStringBacktick */ .chroma .sb { color: #dd1144 }\n/* LiteralStringChar */ .chroma .sc { color: #dd1144 }\n/* LiteralStringDelimiter */ .chroma .dl { color: #dd1144 }\n/* LiteralStringDoc */ .chroma .sd { color: #dd1144 }\n/* LiteralStringDouble */ .chroma .s2 { color: #dd1144 }\n/* LiteralStringEscape */ .chroma .se { color: #dd1144 }\n/* LiteralStringHeredoc */ .chroma .sh { color: #dd1144 }\n/* LiteralStringInterpol */ .chroma .si { color: #dd1144 }\n/* LiteralStringOther */ .chroma .sx { color: #dd1144 }\n/* LiteralStringRegex */ .chroma .sr { color: #009926 }\n/* LiteralStringSingle */ .chroma .s1 { color: #dd1144 }\n/* LiteralStringSymbol */ .chroma .ss { color: #990073 }\n/* LiteralNumber */ .chroma .m { color: #009999 }\n/* LiteralNumberBin */ .chroma .mb { color: #009999 }\n/* LiteralNumberFloat */ .chroma .mf { color: #009999 }\n/* LiteralNumberHex */ .chroma .mh { color: #009999 }\n/* LiteralNumberInteger */ .chroma .mi { color: #009999 }\n/* LiteralNumberIntegerLong */ .chroma .il { color: #009999 }\n/* LiteralNumberOct */ .chroma .mo { color: #009999 }\n/* Operator */ .chroma .o { color: #000000; font-weight: bold }\n/* OperatorWord */ .chroma .ow { color: #000000; font-weight: bold }\n/* Punctuation */ .chroma .p { }\n/* Comment */ .chroma .c { color: #999988; font-style: italic }\n/* CommentHashbang */ .chroma .ch { color: #999988; font-style: italic }\n/* CommentMultiline */ .chroma .cm { color: #999988; font-style: italic }\n/* CommentSingle */ .chroma .c1 { color: #999988; font-style: italic }\n/* CommentSpecial */ .chroma .cs { color: #999999; font-weight: bold; font-style: italic }\n/* CommentPreproc */ .chroma .cp { color: #999999; font-weight: bold; font-style: italic }\n/* CommentPreprocFile */ .chroma .cpf { color: #999999; font-weight: bold; font-style: italic }\n/* Generic */ .chroma .g { }\n/* GenericDeleted */ .chroma .gd { color: #000000; background-color: #ffdddd }\n/* GenericEmph */ .chroma .ge { color: #000000; font-style: italic }\n/* GenericError */ .chroma .gr { color: #aa0000 }\n/* GenericHeading */ .chroma .gh { color: #999999 }\n/* GenericInserted */ .chroma .gi { color: #000000; background-color: #ddffdd }\n/* GenericOutput */ .chroma .go { color: #888888 }\n/* GenericPrompt */ .chroma .gp { color: #555555 }\n/* GenericStrong */ .chroma .gs { font-weight: bold }\n/* GenericSubheading */ .chroma .gu { color: #aaaaaa }\n/* GenericTraceback */ .chroma .gt { color: #aa0000 }\n/* GenericUnderline */ .chroma .gl { text-decoration: underline }\n/* TextWhitespace */ .chroma .w { color: #bbbbbb }\n" + ], + "names": [], + "mappings": "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" +} \ No newline at end of file diff --git a/public/css/style.4c42aa0abeac804c4933c54677c449cea1f723caae778425d031e98565a0cdef.css b/public/css/style.4c42aa0abeac804c4933c54677c449cea1f723caae778425d031e98565a0cdef.css new file mode 100644 index 00000000..5a56b467 --- /dev/null +++ b/public/css/style.4c42aa0abeac804c4933c54677c449cea1f723caae778425d031e98565a0cdef.css @@ -0,0 +1,965 @@ +/* Basic */ + +:root { + --card-border-radius: 0.5em; + --card-margin: 1.5em; + --icon-margin-left: 1em; + --icon-margin-top: 1em; +} + +html { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + /* 1 */ + -ms-text-size-adjust: 100%; + /* 2 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + scroll-behavior: smooth; +} + +body { + margin: 0; + font-size: 18px; + line-height: 1.5; + -webkit-font-smoothing: antialiased; + color: var(--font-color); + background: var(--bg-color); +} + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section { + display: block; +} + +.container { + max-width: 42em; + margin: 0 auto; +} + +main { + outline: none; +} + +/* Table of Contents */ + +.toc { + cursor: zoom-in; + display: block; + + margin-top: 1em; + margin-bottom: 1em; + padding: 0.5em 1em; + /* top & bottom, left & right */ + + border: 1px solid var(--card-border-color); + border-radius: var(--card-border-radius); + background: var(--card-color); + + font-size: 14px; + font-weight: bold; +} + +.toc.expanded { + cursor: zoom-out; +} + +.toc .inner { + margin: 0px; + padding: 0px; +} + +/* Headers */ +h1 { + font-size: 1.35em; +} + +h2 { + font-size: 1.2em; + margin-top: 3em; +} + +h2:first-of-type { + margin-top: 0; +} + +h3 { + font-size: 1.1em; +} + +/* Links */ + +a { + color: var(--link-color); + text-decoration: none; + border-bottom: 1px solid transparent; +} + +a:hover, +a:focus, +a:active { + color: var(--link-state-color); + border-bottom: 1px solid var(--link-state-border-color); +} + +a:active, +a:hover { + outline: 0; +} + +a:active { + opacity: 0.9; +} + +a.skip-main { + left: -999px; + position: absolute; + top: auto; + width: 1px; + height: 1px; + overflow: hidden; + z-index: -999; +} + +a.skip-main:focus, +a.skip-main:active { + left: auto; + top: 0px; + width: auto; + height: auto; + overflow: auto; + z-index: 999; + padding: 4px 6px 4px 6px; + text-decoration: underline; + border: none; +} + +/* Table */ +thead { + background: var(--thead-bg-color); +} + +.table-wrapper { + overflow-x: auto; +} + +table { + max-width: 100%; + display: block; + overflow: scroll; + border-spacing: 0; + border-collapse: collapse; + border-top-left-radius: 6px; + border-top-right-radius: 6px; + font-size: 14px; +} + +th, +td { + padding: 0.25em 0.5em; + border: 1px double var(--table-border-color); + +} + +/* Code */ +mark { + border-radius: 4px; +} + +code, +pre, +kbd { + color: var(--pre-color); + background-color: var(--pre-bg-color); + font-family: 'Menlo', 'Courier New', 'Consolas', monospace; + font-size: 14.4px; + /* 18px * 0.6 */ + line-height: 154%; + border-radius: 6px; + border: 1px solid var(--pre-border-color); + overflow: scroll; +} + +/* tag */ +code { + font-size: 14.4px; + /* 18px * 0.6 */ + padding: 0.1em 0.3em; +} + +pre { + padding: 0.3em; +} + +/* inside

    */ +/* inside

     */
    +/* p kbd,
    +pre kbd {
    +    background-color: transparent;
    +    border: none;
    +} */
    +p kbd,
    +pre kbd,
    +p kbd kbd,
    +pre kbd kbd {
    +    font-size: 14.4px;
    +    /* 18px * 0.6 */
    +    background-color: var(--kbd-bg-color);
    +    border: 1px solid var(--pre-border-color);
    +    border-width: 1px 2px 2px 1px;
    +    padding: 0.1em 0.3em;
    +    margin-left: 0.2em;
    +    margin-right: 0.2em;
    +}
    +
    +p code,
    +p kbd {
    +    padding: 0.1em 0.3em;
    +    /* top, bottom */
    +    /* margin-right: 4px; */
    +}
    +
    +td pre {
    +    border: none;
    +    /* padding: 0px; */
    +    border-radius: 0px;
    +}
    +
    +td:first-child pre {
    +    padding-right: 0;
    +}
    +
    +td:last-child pre {
    +    padding-left: 0;
    +}
    +
    +td pre code {
    +    /* when there is a line number grid */
    +    padding: 0px;
    +    display: flex;
    +    flex-direction: column;
    +    border-radius: 0px;
    +    /* padding-top: 4px; */
    +    /* padding-bottom: 4px; */
    +}
    +
    +div.highlight {
    +    border-radius: 6px;
    +    border: 1px solid var(--pre-border-color);
    +    margin-bottom: 14px;
    +}
    +
    +div.highlight div {
    +    overflow: scroll;
    +}
    +
    +div.highlight pre {
    +    border: none;
    +    display: grid;
    +    margin: 0px;
    +    overflow: auto;
    +    /* Have to add this line, otherwise the "pre" and "code" will have different width */
    +    /* padding-left: 10px; */
    +    /* padding-right: 10px; */
    +    /* padding-top: 10px; */
    +    /* padding-bottom: 10px; */
    +}
    +
    +div.highlight code {
    +    padding-left: 0px;
    +    padding-right: 0px;
    +    overflow: unset;
    +}
    +
    +div.highlight code a:hover,
    +div.highlight code a:focus {
    +    color: white;
    +    border-bottom: 1px solid white;
    +    /*for markup.highlight.anchorLineNos = true*/
    +}
    +
    +pre code,
    +pre kbd {
    +    color: inherit;
    +    background-color: inherit;
    +    border: none;
    +    padding: 0em;
    +}
    +
    +/* Styles */
    +
    +blockquote {
    +    border-left: 2px solid var(--bq-color);
    +    padding: 0.1em 1em;
    +    margin-left: 0.75em;
    +}
    +
    +p {
    +    margin-top: 0.5em;
    +    margin-bottom: 0.5em;
    +}
    +
    +hr {
    +    color: var(--hr-color);
    +    background-color: var(--hr-color);
    +    border: none;
    +    height: 1px;
    +}
    +
    +/* Header */
    +
    +.common-header {
    +    padding-bottom: 1.5em;
    +    /* border-bottom: thin solid var(--hr-color); */
    +}
    +
    +header a {
    +    color: var(--font-color);
    +}
    +
    +header h1 {
    +    font-size: 1em;
    +    margin-top: 1em;
    +    margin-bottom: 0;
    +    font-weight: normal;
    +}
    +
    +header h2 {
    +    font-size: 1em;
    +    margin: 0;
    +    font-weight: normal;
    +}
    +
    +.header-top {
    +    display: flex;
    +    flex-wrap: wrap;
    +    align-items: center;
    +    justify-content: space-between;
    +    vertical-align: middle;
    +    margin-top: 1em;
    +}
    +
    +.header-top-left {
    +    display: flex;
    +    align-items: center;
    +    justify-content: space-between;
    +}
    +
    +.site-title {
    +    display: inline;
    +    white-space: nowrap;
    +    font-weight: 700;
    +}
    +
    +header nav:not(:empty) {
    +    background: var(--nav-bg-color);
    +    margin-top: var(--card-margin);
    +    max-width: 100%;
    +    text-align: center;
    +    padding: 0.5em 0;
    +    border: 1px solid var(--card-border-color);
    +    border-radius: var(--card-border-radius);
    +    font-size: 14px;
    +}
    +
    +header nav a {
    +    display: inline-block;
    +    margin: 0 2.5%;
    +}
    +
    +/* Social icons */
    +.social-icons {
    +    display: inline;
    +    margin: var(--icon-margin-top) 0 0 var(--icon-margin-left);
    +    padding: 0;
    +    list-style-type: none;
    +}
    +
    +.social-icons li {
    +    display: inline;
    +}
    +
    +.social-icons li:not(:first-of-type) {
    +    margin-left: var(--icon-margin-left);
    +}
    +
    +.social-icons a:hover,
    +.social-icons a:focus,
    +.social-icons a:active {
    +    color: inherit;
    +    border-bottom: none;
    +    text-decoration: none;
    +}
    +
    +.inline-svg {
    +    display: inline-block;
    +    height: 1.15rem;
    +    width: 1.15rem;
    +    top: 0.15rem;
    +    position: relative;
    +}
    +
    +
    +/* Pages */
    +main h1 {
    +    margin-top: 1em;
    +    font-weight: normal;
    +    line-height: 1.1em;
    +    margin-bottom: 0.5em;
    +    font-weight: 600;
    +}
    +
    +.post-card {
    +    border: 1px solid var(--card-border-color) !important;
    +    border-radius: 0.5em;
    +    padding: 0em 1em 1em 1em;
    +    background: var(--card-color);
    +}
    +
    +article:not(:last-of-type) {
    +    margin-bottom: var(--card-margin);
    +}
    +
    +.post-short-list:first-of-type {
    +    margin-top: 1em;
    +}
    +
    +.post-short-list img {
    +    max-width: 100%;
    +    display: block;
    +    height: auto;
    +    margin: 0 auto .5em;
    +}
    +
    +.post-short-list video {
    +    max-width: 100%;
    +    display: block;
    +    height: auto;
    +    margin: 0 auto .5em;
    +}
    +
    +/* Articles */
    +
    +.post-header {
    +    margin-top: 1em;
    +    line-height: 1.1em;
    +    margin-bottom: 1em;
    +}
    +
    +.post-header header {
    +    display: inline;
    +}
    +
    +.post-navigation {
    +    background: var(--nav-bg-color);
    +    text-align: center;
    +    margin-top: 1em;
    +    max-width: 100%;
    +    padding: 0.5em 0;
    +}
    +
    +.post-navigation a:first-of-type {
    +    margin-left: 0;
    +}
    +
    +.post-navigation a {
    +    color: var(--nav-link-color);
    +    margin-left: 2em;
    +}
    +
    +.post-navigation a:hover,
    +.post-navigation a:focus,
    +.post-navigation a:active {
    +    color: var(--link-state-color);
    +}
    +
    +.post-list {
    +    border: #777;
    +}
    +
    +.post-short-list .post-title {
    +    display: inline;
    +}
    +
    +.post-title.favorite::after {
    +    content: "🌟";
    +    display: inline-block;
    +    margin-left: 0.2em;
    +}
    +
    +.post-title.draft::after {
    +    content: "✏️";
    +    display: inline-block;
    +    margin-left: 0.2em;
    +}
    +
    +.post-title.favorite.draft::after {
    +    content: "🌟 ✏️";
    +    display: inline-block;
    +    margin-left: 0.2em;
    +}
    +
    +/* article:not(:last-of-type) {
    +    border-bottom: thin solid var(--hr-color);
    +    padding-bottom: 2em;
    +} */
    +
    +article header h1 {
    +    font-size: 1.35em;
    +    line-height: 1.1em;
    +    margin-bottom: 0.5em;
    +    font-weight: 600;
    +    display: inline;
    +}
    +
    +article header h1 a {
    +    color: var(--font-color);
    +    border: none;
    +    text-decoration: none;
    +}
    +
    +.post h1,
    +.post h2,
    +.post h3,
    +.post h4,
    +.post h5,
    +.post h6 {
    +    position: relative;
    +}
    +
    +.post h1 a,
    +.post h2 a,
    +.post h3 a,
    +.post h4 a,
    +.post h5 a,
    +.post h6 a {
    +    opacity: 1;
    +    border-bottom: none;
    +}
    +
    +.post h1:hover a,
    +.post h2:hover a,
    +.post h3:hover a,
    +.post h4:hover a,
    +.post h5:hover a,
    +.post h6:hover a {
    +    opacity: 1;
    +    border-bottom: none;
    +}
    +
    +.post h1 a:hover,
    +.post h1 a:focus,
    +.post h1 a:active,
    +.post h2 a:hover,
    +.post h2 a:focus,
    +.post h2 a:active,
    +.post h3 a:hover,
    +.post h3 a:focus,
    +.post h3 a:active,
    +.post h4 a:hover,
    +.post h4 a:focus,
    +.post h4 a:active,
    +.post h5 a:hover,
    +.post h5 a:focus,
    +.post h5 a:active,
    +.post h6 a:hover,
    +.post h6 a:focus,
    +.post h6 a:active {
    +    border-bottom: none;
    +}
    +
    +.post h1 svg,
    +.post h2 svg,
    +.post h3 svg,
    +.post h4 svg,
    +.post h5 svg,
    +.post h6 svg {
    +    stroke: var(--svg-color);
    +}
    +
    +.post h1 svg:hover,
    +.post h1 svg:focus,
    +.post h1 svg:active,
    +.post h2 svg:hover,
    +.post h2 svg:focus,
    +.post h2 svg:active,
    +.post h3 svg:hover,
    +.post h3 svg:focus,
    +.post h3 svg:active,
    +.post h4 svg:hover,
    +.post h4 svg:focus,
    +.post h4 svg:active,
    +.post h5 svg:hover,
    +.post h5 svg:focus,
    +.post h5 svg:active,
    +.post h6 svg:hover,
    +.post h6 svg:focus,
    +.post h6 svg:active {
    +    stroke: var(--svg-state-color);
    +}
    +
    +.post-list .post-info {
    +    color: var(--post-info-color);
    +    font-size: 0.75em;
    +    margin-top: 1em;
    +    margin-bottom: 1em;
    +    display: block;
    +    gap: 1em;
    +}
    +
    +.post-info {
    +    color: var(--post-info-color);
    +    font-size: 0.75em;
    +    margin-top: 1em;
    +    margin-bottom: 1em;
    +    display: flex;
    +    gap: 1em;
    +}
    +
    +.post-info a {
    +    color: var(--post-info-color);
    +}
    +
    +.post-info a:hover {
    +    color: var(--link-state-color);
    +}
    +
    +.post-short-list .post-info {
    +    margin-top: 0;
    +    margin-bottom: 1.5em;
    +}
    +
    +.post-taxonomies {
    +    display: inline;
    +}
    +
    +.post-hidden-url {
    +    display: none;
    +}
    +
    +.post-hidden-author {
    +    display: none;
    +}
    +
    +.post-date {
    +    white-space: nowrap;
    +}
    +
    +.post-categories {
    +    display: inline;
    +    list-style-type: none;
    +    padding: 0;
    +}
    +
    +.post-categories li {
    +    display: inline;
    +    margin-right: 1em;
    +}
    +
    +.post-tags {
    +    display: inline;
    +    list-style-type: none;
    +    padding: 0;
    +    margin: 0;
    +}
    +
    +.post-tags li {
    +    display: inline;
    +    margin-right: 1em;
    +}
    +
    +.post-authors {
    +    display: inline;
    +    list-style-type: none;
    +    padding: 0;
    +    margin: 0;
    +}
    +
    +.post-authors li {
    +    display: inline;
    +    margin-right: 1em;
    +}
    +
    +article img {
    +    max-width: 100%;
    +    display: block;
    +    height: auto;
    +    margin: 0 auto .5em;
    +}
    +
    +article figcaption {
    +    color: grey;
    +    text-align: center;
    +    font-size: 0.85em;
    +    margin-bottom: 2em;
    +}
    +
    +article video {
    +    max-width: 100%;
    +    display: block;
    +    height: auto;
    +    margin: 0 auto .5em;
    +}
    +
    +code.has-jax {
    +    -webkit-font-smoothing: antialiased;
    +    background: inherit !important;
    +    border: none !important;
    +    font-size: 100%;
    +}
    +
    +.read-more {
    +    margin: 1em 0;
    +}
    +
    +.divider {
    +    border-top: thin solid var(--hr-color);
    +    display: block;
    +    height: 1px;
    +    border: 0;
    +    width: 25%;
    +    margin: 1em auto;
    +}
    +
    +.post-summary {
    +    margin-top: 0.5em;
    +    display: block;
    +}
    +
    +.post-summary>p {
    +    display: block;
    +}
    +
    +.post-translations {
    +    margin-left: 0.5em;
    +    list-style: none;
    +    padding: 0;
    +    display: inline;
    +    font-size: 14px;
    +}
    +
    +.post-translations>li {
    +    display: inline;
    +}
    +
    +.post-translations>li:not(:last-child)::after {
    +    content: "|";
    +    display: inline-block;
    +    margin-left: 4px;
    +    margin-right: 4px;
    +}
    +
    +.post-translations>li a {
    +    color: var(--link-color);
    +}
    +
    +.post-translations>li a:hover,
    +.post-translations>li a:focus {
    +    color: var(--link-state-color);
    +}
    +
    +.read-next-title {
    +    margin-bottom: 0;
    +    margin-top: 3em;
    +    padding-top: 1em;
    +    border-top: 1px dashed var(--thead-bg-color);
    +}
    +
    +.read-next-posts {
    +    margin-top: 5px;
    +    list-style-type: "- ";
    +    padding-inline-start: 20px;
    +}
    +
    +/* Other pages */
    +.terms {
    +    list-style-type: none;
    +    padding: 0;
    +    line-height: 2em;
    +}
    +
    +/* Pagination */
    +
    +.pagination {
    +    display: flex;
    +    justify-content: space-between;
    +    margin-top: 3em;
    +    text-align: center;
    +}
    +
    +.pagination-item {
    +    border: 1px solid var(--pagination-border-color);
    +    border-radius: var(--pagination-border-radius);
    +    background: var(--pagination-bg-color);
    +    padding: 0.25em 0.75em;
    +}
    +
    +.pagination-item a {
    +    color: var(--pagination-link-color);
    +}
    +
    +.pagination-item a:hover,
    +.pagination-item a:focus {
    +    color: var(--link-state-color);
    +}
    +
    +.disabled {
    +    visibility: hidden;
    +}
    +
    +.pagination-item a:hover,
    +.pagination-item a:focus {
    +    border-bottom: 0;
    +}
    +
    +.post-pagination .pagination-item {
    +    overflow: hidden;
    +    text-overflow: ellipsis;
    +    white-space: nowrap;
    +    max-width: 16em;
    +}
    +
    +/* Footer */
    +
    +.common-footer {
    +    padding-top: 1.5em;
    +    margin-top: 3em;
    +    font-size: 12px;
    +    margin-bottom: 1.5em;
    +    color: var(--pagination-link-color);
    +}
    +
    +.common-footer-bottom {
    +    display: flex;
    +    flex-wrap: wrap;
    +    align-items: center;
    +    justify-content: space-between;
    +}
    +
    +ul.language-select,
    +ul.footer-menu {
    +    padding-left: 0;
    +    list-style: none;
    +    display: flex;
    +}
    +
    +ul.language-select>li,
    +ul.footer-menu>li {
    +    margin-right: 1em;
    +}
    +
    +.theme-switcher {
    +    color: var(--switcher-color);
    +    /* padding: 0.5em 1em; */
    +    margin: var(--icon-margin-top) 0 0 var(--icon-margin-left);
    +    cursor: pointer;
    +}
    +
    +.h-card {
    +    display: none;
    +}
    +
    +/* Copy code  */
    +.highlight {
    +    position: relative;
    +    overflow: hidden;
    +}
    +
    +.highlight:hover .highlight-copy-btn {
    +    display: inline-block;
    +    border: 1px solid rgba(0, 0, 0, 0.5);
    +}
    +
    +.highlight-copy-btn {
    +    display: none;
    +    position: absolute;
    +    top: 0px;
    +    right: 0px;
    +    border: 1px solid rgba(0, 0, 0, 0.5);
    +    border-radius: 6px;
    +    padding: 1px;
    +    font-size: 0.7em;
    +    line-height: 1.8;
    +    color: #fff;
    +    background-color: rgba(255, 255, 255, 0.1);
    +    min-width: 22px;
    +    text-align: center;
    +    transition: border 0.3s;
    +    transition: background-color 0.3s;
    +}
    +
    +.highlight-copy-btn:hover {
    +    transition-duration: .1s;
    +    background-color: rgba(255, 255, 255, 0.3);
    +    cursor: pointer;
    +}
    +
    +.highlight-copy-btn,
    +.highlight-copy-btn svg {
    +    vertical-align: middle;
    +    margin: 8px;
    +}
    +
    +/* Others */
    +.noselect {
    +    -webkit-touch-callout: none;
    +    /* iOS Safari */
    +    -webkit-user-select: none;
    +    /* Safari */
    +    -khtml-user-select: none;
    +    /* Konqueror HTML */
    +    -moz-user-select: none;
    +    /* Firefox */
    +    -ms-user-select: none;
    +    /* Internet Explorer/Edge */
    +    user-select: none;
    +    /* Non-prefixed version, currently
    +                                    supported by Chrome and Opera */
    +}
    +
    +
    +/* Media Queries */
    +
    +@media (max-width: 840px) {
    +    .main-wrapper {
    +        margin: 0;
    +        max-width: none;
    +        overflow-x: hidden;
    +        padding-left: 25px;
    +        padding-right: 25px;
    +    }
    +
    +    .container {
    +        max-width: 90%;
    +        margin: 0 auto;
    +        word-wrap: break-word;
    +    }
    +
    +    .pagination-item {
    +        padding: 0.5em 0.5em;
    +        font-size: 14px;
    +    }
    +
    +    .post-navigation {
    +        background: var(--pagination-bg-color);
    +        text-align: center;
    +        padding: 0.5em 0;
    +    }
    +
    +    .post-navigation a {
    +        margin-left: 0.5em;
    +    }
    +
    +    .post-pagination .pagination-item {
    +        max-width: 10em;
    +    }
    +}
    \ No newline at end of file
    diff --git a/public/css/style.779ec8e6902530eb27b55bc5845f86cfa59dc8ffedf4c6fdc6377c90b514db02.css b/public/css/style.779ec8e6902530eb27b55bc5845f86cfa59dc8ffedf4c6fdc6377c90b514db02.css
    new file mode 100644
    index 00000000..4d4f1bf5
    --- /dev/null
    +++ b/public/css/style.779ec8e6902530eb27b55bc5845f86cfa59dc8ffedf4c6fdc6377c90b514db02.css
    @@ -0,0 +1,802 @@
    +
    +
    +
    +:root {
    +   /* light.css */ 
    +    --font-color: #333;
    +    --bg-color: #fff;
    +
    +    --link-color:#1d60a3;
    +    --link-state-color:#a31d1d;
    +    --link-state-border-color: rgba(163, 29, 29, .5);
    +
    +    --thead-bg-color: lightgrey;
    +    --table-border-color: lightgrey;
    +
    +    --nav-bg-color: #fafafa;
    +    --nav-link-color: #696969;
    +
    +    --pre-color: #f8f8f2;
    +    --pre-bg-color: #272822;
    +
    +    --bq-color: #ccc;
    +    --hr-color: #ccc;
    +
    +    --pagination-bg-color: #fafafa;
    +    --pagination-link-color: #696969;
    +
    +    --post-info-color: grey;
    +
    +    --switcher-color: #fff;
    +    --switcher-bg-color: #333; 
    +
    +    --svg-color: #333;
    +    --svg-state-color: #a31d1d;
    +}
    +
    +
    +
    +[data-theme="dark"] {
    +    /* dark.css */ 
    +--font-color: #eee;
    +--bg-color: #212121;
    +
    +--link-color:#599ada;
    +--link-state-color:#ff5858;
    +--link-state-border-color: rgba(238, 54, 54, 0.5);
    +
    +--thead-bg-color: #343a40;
    +--table-border-color: lightgrey;
    +
    +--nav-bg-color: #242424;
    +--nav-link-color: #b6b6b6;
    +
    +--pre-color: #f8f8f2;
    +--pre-bg-color: #272822;
    +
    +--bq-color: #ccc;
    +--hr-color: #333;
    +
    +--pagination-bg-color: #373737;
    +--pagination-link-color: #b6b6b6;
    +
    +--post-info-color: grey;
    +
    +--switcher-color: #333;
    +--switcher-bg-color: #fff;
    +
    +--svg-color: #ccc;
    +--svg-state-color:#ff5858;
    +
    +}
    +
    +
    +/* Basic */
    +html {
    +    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
    +    /* 1 */
    +    -ms-text-size-adjust: 100%;
    +    /* 2 */
    +    -webkit-text-size-adjust: 100%;
    +    /* 2 */
    +}
    +
    +body {
    +    margin: 0;
    +    font-size: 18px;
    +    line-height: 1.5;
    +    -webkit-font-smoothing: antialiased;
    +    color: var(--font-color);
    +    background: var(--bg-color);
    +}
    +
    +article,
    +aside,
    +details,
    +figcaption,
    +figure,
    +footer,
    +header,
    +hgroup,
    +main,
    +menu,
    +nav,
    +section {
    +    display: block;
    +}
    +
    +.container {
    +    max-width: 42em;
    +    margin: 0 auto;
    +}
    +
    +main {
    +    outline:none;
    +}
    +
    +/* Headers */
    +h1 {
    +    font-size: 1.35em;
    +}
    +
    +h2 {
    +    font-size: 1.2em;
    +}
    +
    +h3 {
    +    font-size: 1.1em;
    +}
    +
    +/* Links */
    +
    +a {
    +    color: var(--link-color);
    +    text-decoration: none;
    +    border-bottom: 1px solid transparent;
    +}
    +
    +a:hover,
    +a:focus,
    +a:active {
    +    color: var(--link-state-color);
    +    border-bottom: 1px solid var(--link-state-border-color);
    +}
    +
    +a:active,
    +a:hover {
    +    outline: 0;
    +}
    +
    +a:active {
    +    opacity: 0.9;
    +}
    +
    +a.skip-main {
    +    left:-999px;
    +    position:absolute;
    +    top:auto;
    +    width:1px;
    +    height:1px;
    +    overflow:hidden;
    +    z-index:-999;
    +}
    +
    +a.skip-main:focus,
    +a.skip-main:active {
    +    left: auto;
    +    top: 0px;
    +    width: auto;
    +    height: auto;
    +    overflow:auto;
    +    z-index:999;
    +    padding: 4px 6px 4px 6px;
    +    text-decoration: underline;
    +    border: none;
    +}
    +
    +/* Table */
    +thead {
    +    background: var(--thead-bg-color);
    +}
    +
    +.table-wrapper {
    +    overflow-x: auto;
    +}
    +
    +table {
    +    max-width: 100%;
    +    border-spacing: 0;
    +}
    +
    +
    +th, td {
    +    padding: 0.5em 1em;
    +    border: 1px double var(--table-border-color);
    +}
    +
    +/* Code */
    +pre {
    +    padding: 1em;
    +    max-width: 100%;
    +    overflow: auto;
    +}
    +
    +code,
    +pre,
    +kbd {
    +    color: var(--pre-color);
    +    background-color: var(--pre-bg-color);
    +    font-family: monospace;
    +    font-size: 0.90em;
    +    line-height: 154%;
    +}
    +
    +pre code, pre kbd {
    +    color: inherit;
    +    background-color: inherit;
    +}
    +
    +/* Styles */
    +
    +blockquote {
    +    border-left: 2px solid var(--bq-color);
    +    padding: 0.1em 1em;
    +    margin-left: 0.75em;
    +}
    +
    +p {
    +    margin-top: 0.5em;
    +    margin-bottom: 0.5em;
    +}
    +
    +hr {
    +    color: var(--hr-color);
    +    background-color: var(--hr-color);
    +    border: none;
    +    height: 1px;
    +}
    +
    +/* Header */
    +
    +.common-header {
    +    padding-bottom: 1.5em;
    +    border-bottom: thin solid var(--hr-color);
    +}
    +
    +header a {
    +    color: var(--font-color);
    +}
    +
    +header h1 {
    +    font-size: 1em;
    +    margin-top: 1em;
    +    margin-bottom: 0;
    +    font-weight: normal;
    +}
    +
    +header h2 {
    +    font-size: 1em;
    +    margin: 0;
    +    font-weight: normal;
    +}
    +
    +.header-top {
    +    display: flex;
    +    flex-wrap: wrap;
    +    align-items: center;
    +    justify-content: space-between;
    +    vertical-align: middle;
    +}
    +
    +.site-title {
    +    white-space: nowrap;
    +}
    +
    +header nav:not(:empty){
    +    background: var(--nav-bg-color);
    +    margin-top: 1em;
    +    max-width: 100%;
    +    text-align: center;
    +    padding: 0.5em 0;
    +}
    +
    +header nav a {
    +    display: inline-block;
    +    margin: 0 2.5%;
    +}
    +
    +/* Social icons */
    +.social-icons {
    +    margin-top: 1em;
    +    margin-bottom: 0;
    +    padding: 0;
    +    list-style-type: none;
    +}
    +
    +.social-icons li {
    +    display: inline;
    +}
    +
    +.social-icons li:not(:first-of-type) {
    +    margin-left: 0.5em;
    +}
    +
    +.social-icons a:hover,
    +.social-icons a:focus,
    +.social-icons a:active {
    +    color: inherit;
    +    border-bottom: none;
    +    text-decoration: none;
    +}
    +
    +.inline-svg {
    +    display: inline-block;
    +    height: 1.15rem;
    +    width: 1.15rem;
    +    top: 0.15rem;
    +    position: relative;
    +}
    +
    +
    +/* Pages */
    +main h1 {
    +    margin-top: 1em;
    +    font-weight: normal;
    +    line-height: 1.1em;
    +    margin-bottom: 0.5em;
    +    font-weight: 600;
    +}
    +
    +.post-short-list:first-of-type {
    +    margin-top: 1em;
    +}
    +
    +/* Articles */
    +
    +.post-header {
    +    margin-top: 1em;
    +    line-height: 1.1em;
    +    margin-bottom: 1em;
    +}
    +
    +.post-header header {
    +    display: inline;
    +}
    +
    +.post-navigation {
    +    background: var(--nav-bg-color);
    +    text-align: center;
    +    margin-top: 1em;
    +    max-width: 100%;
    +    padding: 0.5em 0;
    +}
    +
    +.post-navigation a:first-of-type {
    +    margin-left: 0;
    +}
    +
    +.post-navigation a {
    +    color: var(--nav-link-color);
    +    margin-left: 2em;
    +}
    +
    +.post-navigation a:hover,
    +.post-navigation a:focus,
    +.post-navigation a:active {
    +    color: var(--link-state-color);
    +}
    +
    +.post-short-list .post-title {
    +    display: inline;
    +}
    +
    +.post-title.favorite::after {
    +    content: "☆";
    +    display: inline-block;
    +    margin-left: 0.2em;
    +}
    +
    +.post-title.draft::after {
    +    content: "✎";
    +    display: inline-block;
    +    margin-left: 0.2em;
    +}
    +
    +.post-title.favorite.draft::after {
    +    content: "☆ ✎";
    +    display: inline-block;
    +    margin-left: 0.2em;
    +}
    +
    +article:not(:last-of-type) {
    +    border-bottom: thin solid var(--hr-color);
    +    padding-bottom: 2em;
    +}
    +
    +article header h1 {
    +    font-size: 1.35em;
    +    line-height: 1.1em;
    +    margin-bottom: 0.5em;
    +    font-weight: 600;
    +    display: inline;
    +}
    +
    +article header h1 a {
    +    color: var(--font-color);
    +    border: none;
    +    text-decoration: none;
    +}
    +
    +.post h1,
    +.post h2,
    +.post h3,
    +.post h4,
    +.post h5,
    +.post h6 {
    +    position: relative;
    +}
    +
    +.post h1 a,
    +.post h2 a,
    +.post h3 a,
    +.post h4 a,
    +.post h5 a,
    +.post h6 a {
    +    opacity: 0;
    +    position: absolute;
    +    left: -1.2rem;
    +}
    +
    +.post h1:hover a,
    +.post h2:hover a,
    +.post h3:hover a,
    +.post h4:hover a,
    +.post h5:hover a,
    +.post h6:hover a {
    +    opacity: 1;
    +    border-bottom: none;
    +}
    +
    +.post h1 a:hover,
    +.post h1 a:focus,
    +.post h1 a:active,
    +.post h2 a:hover,
    +.post h2 a:focus,
    +.post h2 a:active,
    +.post h3 a:hover,
    +.post h3 a:focus,
    +.post h3 a:active,
    +.post h4 a:hover,
    +.post h4 a:focus,
    +.post h4 a:active,
    +.post h5 a:hover,
    +.post h5 a:focus,
    +.post h5 a:active,
    +.post h6 a:hover,
    +.post h6 a:focus,
    +.post h6 a:active {
    +    border-bottom: none;
    +}
    +
    +.post h1 svg,
    +.post h2 svg,
    +.post h3 svg,
    +.post h4 svg,
    +.post h5 svg,
    +.post h6 svg {
    +    stroke: var(--svg-color);
    +}
    +
    +.post h1 svg:hover,
    +.post h1 svg:focus,
    +.post h1 svg:active,
    +.post h2 svg:hover,
    +.post h2 svg:focus,
    +.post h2 svg:active,
    +.post h3 svg:hover,
    +.post h3 svg:focus,
    +.post h3 svg:active,
    +.post h4 svg:hover,
    +.post h4 svg:focus,
    +.post h4 svg:active,
    +.post h5 svg:hover,
    +.post h5 svg:focus,
    +.post h5 svg:active,
    +.post h6 svg:hover,
    +.post h6 svg:focus,
    +.post h6 svg:active {
    +    stroke: var(--svg-state-color);
    +}
    +
    +.post-info {
    +    color: var(--post-info-color);
    +    font-size: 0.75em;
    +    margin-top: 1em;
    +}
    +
    +.post-info a {
    +    color: var(--post-info-color);
    +}
    +
    +.post-info a:hover {
    +    color: var(--link-state-color);
    +}
    +
    +.post-short-list .post-info {
    +    margin-top: 0;
    +    margin-bottom: 1.5em;
    +}
    +
    +.post-taxonomies {
    +    display: inline;
    +}
    +
    +.post-hidden-url {
    +    display: none;
    +}
    +
    +.post-hidden-author {
    +    display: none;
    +}
    +
    +.post-date {
    +    white-space: nowrap;
    +}
    +
    +.post-categories {
    +    display: inline;
    +    list-style-type: none;
    +    padding: 0;
    +}
    +
    +.post-categories li {
    +    display: inline;
    +    margin-right: 1em;
    +}
    +
    +.post-tags {
    +    display: inline;
    +    list-style-type: none;
    +    padding: 0;
    +    margin: 0;
    +}
    +
    +.post-tags li {
    +    display: inline;
    +    margin-right: 1em;
    +}
    +
    +article img {
    +    max-width: 100%;
    +    display: block;
    +    height: auto;
    +    margin: 0 auto .5em;
    +}
    +
    +article figcaption {
    +    color: grey;
    +    text-align: center;
    +    font-size: 0.85em;
    +    margin-bottom: 2em;
    +}
    +
    +code.has-jax {
    +    -webkit-font-smoothing: antialiased;
    +    background: inherit !important;
    +    border: none !important;
    +    font-size: 100%;
    +}
    +
    +.read-more {
    +    margin: 1em 0;
    +}
    +
    +.divider {
    +    border-top: thin solid var(--hr-color);
    +    display: block;
    +    height: 1px;
    +    border: 0;
    +    width: 25%;
    +    margin: 1em auto;
    +}
    +
    +.post-summary {
    +    margin-top: 0.5em;
    +    display: block;
    +}
    +
    +.post-summary > p {
    +    display: block;
    +}
    +
    +.post-translations {
    +    margin-left: 0.5em;
    +    list-style: none;
    +    padding: 0;
    +    display: inline;
    +    font-size: 14px;
    +}
    +
    +.post-translations > li {
    +    display: inline;
    +}
    +
    +.post-translations > li:not(:last-child)::after {
    +    content: "|";
    +    display: inline-block;
    +}
    +
    +.post-translations > li a {
    +    color: var(--link-color);
    +}
    +
    +.post-translations > li a:hover,
    +.post-translations > li a:focus {
    +    color: var(--link-state-color);
    +}
    +
    +.read-next-title {
    +    margin-bottom:  0;
    +}
    +
    +.read-next-posts {
    +    margin-top:  5px;
    +    list-style-type:"- ";
    +    padding-inline-start: 20px;
    +}
    +
    +/* Other pages */
    +.terms {
    +    list-style-type: none;
    +    padding: 0;
    +    line-height: 2em;
    +}
    +
    +/* Pagination */
    +
    +.pagination {
    +    display: flex;
    +    justify-content: space-between;
    +    margin-top: 3em;
    +    text-align: center;
    +}
    +
    +.pagination-item {
    +    background: var(--pagination-bg-color);
    +    padding: 0.75em 0.75em;
    +}
    +
    +.pagination-item a {
    +    color: var(--pagination-link-color);
    +}
    +
    +.pagination-item a:hover,
    +.pagination-item a:focus {
    +    color: var(--link-state-color);
    +}
    +
    +.disabled {
    +    visibility: hidden;
    +}
    +
    +.pagination-item a:hover, .pagination-item a:focus {
    +    border-bottom: 0;
    +}
    +
    +.post-pagination .pagination-item {
    +    overflow: hidden;
    +    text-overflow: ellipsis;
    +    white-space: nowrap;
    +    max-width: 16em;
    +}
    +
    +/* Footer */
    +
    +.common-footer {
    +    border-top: thin solid var(--hr-color);
    +    padding-top: 1.5em;
    +    margin-top: 3em;
    +    font-size: 16px;
    +}
    +
    +.common-footer-bottom {
    +    display: flex;
    +    flex-wrap: wrap;
    +    align-items: center;
    +    justify-content: space-between;
    +}
    +
    +ul.language-select, ul.footer-menu {
    +    padding-left: 0;
    +    list-style: none;
    +    display: flex;
    +}
    +
    +ul.language-select > li, ul.footer-menu > li {
    +    margin-right: 1em;
    +}
    +
    +.theme-switcher {
    +    color: var(--switcher-color);
    +    background: var(--switcher-bg-color);
    +    padding: 0.5em 1em;
    +    font-size: 16px;
    +    border: none;
    +    margin-bottom: 1em;
    +}
    +
    +.h-card {
    +    display: none;
    +}
    +
    +/* Copy code  */
    +.highlight {
    +    position: relative;
    +    overflow: auto;
    +}
    +.highlight pre {
    +    padding-right: 75px;
    +}
    +
    +.highlight:hover .highlight-copy-btn {
    +    display: inline-block;
    +    border: 1px solid var(--bg-color);
    +}
    +
    +.highlight-copy-btn {
    +    display: none;
    +    position: absolute;
    +    top: 18px;
    +    right: 2px;
    +    border: 0;
    +    border-radius: 4px;
    +    padding: 1px;
    +    font-size: 0.7em;
    +    line-height: 1.8;
    +    color: #fff;
    +    background-color: #777;
    +    min-width: 25px;
    +    text-align: center;
    +    border-radius: 5px;
    +}
    +.highlight-copy-btn:hover {
    +    transition-duration: .1s;
    +    background-color: #666;
    +    border: 1px solid var(--bq-color) !important;
    +    cursor: pointer;
    +}
    +
    +.highlight-copy-btn,
    +.highlight-copy-btn svg {
    +    vertical-align: middle;
    +    margin: 8px;
    +}
    +
    +/* Media Queries */
    +
    +@media (max-width: 840px) {
    +    .main-wrapper {
    +        margin: 0;
    +        max-width: none;
    +        overflow-x: hidden;
    +        padding-left: 25px;
    +        padding-right: 25px;
    +    }
    +
    +    .container {
    +        max-width: 90%;
    +        margin: 0 auto;
    +        word-wrap: break-word;
    +    }
    +
    +    .pagination-item {
    +        padding: 0.5em 0.5em;
    +        font-size: 14px;
    +    }
    +
    +    .post-navigation {
    +        background: var(--pagination-bg-color);
    +        text-align: center;
    +        padding: 0.5em 0;
    +    }
    +
    +    .post-navigation a {
    +        margin-left: 0.5em;
    +    }
    +
    +    .post-pagination .pagination-item {
    +        max-width: 10em;
    +    }
    +}
    +
    +
    +
    +
    +  #isso-thread .textarea {
    +    color: #000;
    +  }
    +  #isso-thread .isso-feedlink {
    +    position: relative;
    +    z-index: 1;
    +  }
    +
    diff --git a/public/css/style.9c1888ebff42c0224ce04dac10cb2c401f1b77f54f78e8d87d73c3bed781c263.css b/public/css/style.9c1888ebff42c0224ce04dac10cb2c401f1b77f54f78e8d87d73c3bed781c263.css
    new file mode 100644
    index 00000000..c1df0e43
    --- /dev/null
    +++ b/public/css/style.9c1888ebff42c0224ce04dac10cb2c401f1b77f54f78e8d87d73c3bed781c263.css
    @@ -0,0 +1,76 @@
    +@media (prefers-color-scheme: light) {
    +  html {
    +    --font-color: #1e1e1e;
    +    --bg-color: #ffffff;
    +
    +    --card-color: #fafafa;
    +    --card-border-color: #eeeeee;
    +
    +    --link-color: #1d60a3;
    +    --link-state-color: rgb(163, 29, 29);
    +    --link-state-border-color: rgba(163, 29, 29, 0.5);
    +
    +    --thead-bg-color: lightgrey;
    +    --table-border-color: lightgrey;
    +
    +    --nav-bg-color: #fafafa;
    +    --nav-link-color: #696969;
    +
    +    --pre-color: rgb(31, 35, 40);
    +    --pre-bg-color: #eff1f2;
    +    --pre-border-color: #e1e5e9;
    +    --kbd-bg-color: #f7f7f7;
    +
    +    --bq-color: #ccc;
    +    --hr-color: #ccc;
    +
    +    --pagination-bg-color: #fafafa;
    +    --pagination-link-color: #696969;
    +    --pagination-border-color: #eeeeee;
    +    --pagination-border-radius: 5px;
    +
    +    --post-info-color: grey;
    +
    +    --switcher-color: #333;
    +
    +    --svg-color: #333;
    +    --svg-state-color: #a31d1d;
    +  }
    +}
    +html[data-theme="light"] {
    +  --font-color: #1e1e1e;
    +  --bg-color: #ffffff;
    +
    +  --card-color: #fafafa;
    +  --card-border-color: #eeeeee;
    +
    +  --link-color: #1d60a3;
    +  --link-state-color: rgb(163, 29, 29);
    +  --link-state-border-color: rgba(163, 29, 29, 0.5);
    +
    +  --thead-bg-color: lightgrey;
    +  --table-border-color: lightgrey;
    +
    +  --nav-bg-color: #fafafa;
    +  --nav-link-color: #696969;
    +
    +  --pre-color: rgb(31, 35, 40);
    +  --pre-bg-color: #eff1f2;
    +  --pre-border-color: #e1e5e9;
    +  --kbd-bg-color: #f7f7f7;
    +
    +  --bq-color: #ccc;
    +  --hr-color: #ccc;
    +
    +  --pagination-bg-color: #fafafa;
    +  --pagination-link-color: #696969;
    +  --pagination-border-color: #eeeeee;
    +  --pagination-border-radius: 5px;
    +
    +  --post-info-color: grey;
    +
    +  --switcher-color: #333;
    +
    +  --svg-color: #333;
    +  --svg-state-color: #a31d1d;
    +}
    diff --git a/public/css/style.acd606c0fce58853afe0248d37bb41acbbcdd8b1aca2412b6c0fa760da0137f3.css b/public/css/style.acd606c0fce58853afe0248d37bb41acbbcdd8b1aca2412b6c0fa760da0137f3.css
    new file mode 100644
    index 00000000..d01d145b
    --- /dev/null
    +++ b/public/css/style.acd606c0fce58853afe0248d37bb41acbbcdd8b1aca2412b6c0fa760da0137f3.css
    @@ -0,0 +1,77 @@
    +@media (prefers-color-scheme: dark) {
    +    html {
    +        --font-color: #dadadb;
    +        --bg-color: #1d1e20;
    +
    +        --card-color: #2e2e33;
    +        --card-border-color: #333333;
    +
    +        --link-color: #599ada;
    +        --link-state-color: #ff5858;
    +        --link-state-border-color: rgba(238, 54, 54, 0.5);
    +
    +        --thead-bg-color: #343a40;
    +        --table-border-color: lightgrey;
    +
    +        --nav-bg-color: #2e2e33;
    +        --nav-link-color: #b6b6b6;
    +
    +        --pre-color: #f8f8f2;
    +        --pre-bg-color: #292b2d;
    +        --pre-border-color: rgba(175, 184, 193, 0.3);
    +        --kbd-bg-color: #404347;
    +
    +        --bq-color: #ccc;
    +        --hr-color: #333;
    +
    +        --pagination-bg-color: #2e2e33;
    +        --pagination-link-color: #b6b6b6;
    +        --pagination-border-color: #333333;
    +        --pagination-border-radius: 5px;
    +
    +        --post-info-color: grey;
    +
    +        --switcher-color: #fff;
    +
    +        --svg-color: #ccc;
    +        --svg-state-color: #ff5858;
    +    }
    +}
    +/* Same as above.  */
    +html[data-theme='dark'] {
    +    --font-color: #dadadb;
    +    --bg-color: #1d1e20;
    +
    +    --card-color: #2e2e33;
    +    --card-border-color: #333333;
    +
    +    --link-color: #599ada;
    +    --link-state-color: #ff5858;
    +    --link-state-border-color: rgba(238, 54, 54, 0.5);
    +
    +    --thead-bg-color: #343a40;
    +    --table-border-color: lightgrey;
    +
    +    --nav-bg-color: #2e2e33;
    +    --nav-link-color: #b6b6b6;
    +
    +    --pre-color: #f8f8f2;
    +    --pre-bg-color: #292b2d;
    +    --pre-border-color: rgba(175, 184, 193, 0.3);
    +    --kbd-bg-color: #404347;
    +
    +    --bq-color: #ccc;
    +    --hr-color: #333;
    +
    +    --pagination-bg-color: #2e2e33;
    +    --pagination-link-color: #b6b6b6;
    +    --pagination-border-color: #333333;
    +    --pagination-border-radius: 5px;
    +
    +    --post-info-color: grey;
    +
    +    --switcher-color: #fff;
    +
    +    --svg-color: #ccc;
    +    --svg-state-color: #ff5858;
    +}
    diff --git a/public/fonts/LICENSE.txt b/public/fonts/LICENSE.txt
    new file mode 100644
    index 00000000..e69c5e39
    --- /dev/null
    +++ b/public/fonts/LICENSE.txt
    @@ -0,0 +1,165 @@
    +Fonticons, Inc. (https://fontawesome.com)
    +
    +--------------------------------------------------------------------------------
    +
    +Font Awesome Free License
    +
    +Font Awesome Free is free, open source, and GPL friendly. You can use it for
    +commercial projects, open source projects, or really almost whatever you want.
    +Full Font Awesome Free license: https://fontawesome.com/license/free.
    +
    +--------------------------------------------------------------------------------
    +
    +# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/)
    +
    +The Font Awesome Free download is licensed under a Creative Commons
    +Attribution 4.0 International License and applies to all icons packaged
    +as SVG and JS file types.
    +
    +--------------------------------------------------------------------------------
    +
    +# Fonts: SIL OFL 1.1 License
    +
    +In the Font Awesome Free download, the SIL OFL license applies to all icons
    +packaged as web and desktop font files.
    +
    +Copyright (c) 2024 Fonticons, Inc. (https://fontawesome.com)
    +with Reserved Font Name: "Font Awesome".
    +
    +This Font Software is licensed under the SIL Open Font License, Version 1.1.
    +This license is copied below, and is also available with a FAQ at:
    +http://scripts.sil.org/OFL
    +
    +SIL OPEN FONT LICENSE
    +Version 1.1 - 26 February 2007
    +
    +PREAMBLE
    +The goals of the Open Font License (OFL) are to stimulate worldwide
    +development of collaborative font projects, to support the font creation
    +efforts of academic and linguistic communities, and to provide a free and
    +open framework in which fonts may be shared and improved in partnership
    +with others.
    +
    +The OFL allows the licensed fonts to be used, studied, modified and
    +redistributed freely as long as they are not sold by themselves. The
    +fonts, including any derivative works, can be bundled, embedded,
    +redistributed and/or sold with any software provided that any reserved
    +names are not used by derivative works. The fonts and derivatives,
    +however, cannot be released under any other type of license. The
    +requirement for fonts to remain under this license does not apply
    +to any document created using the fonts or their derivatives.
    +
    +DEFINITIONS
    +"Font Software" refers to the set of files released by the Copyright
    +Holder(s) under this license and clearly marked as such. This may
    +include source files, build scripts and documentation.
    +
    +"Reserved Font Name" refers to any names specified as such after the
    +copyright statement(s).
    +
    +"Original Version" refers to the collection of Font Software components as
    +distributed by the Copyright Holder(s).
    +
    +"Modified Version" refers to any derivative made by adding to, deleting,
    +or substituting — in part or in whole — any of the components of the
    +Original Version, by changing formats or by porting the Font Software to a
    +new environment.
    +
    +"Author" refers to any designer, engineer, programmer, technical
    +writer or other person who contributed to the Font Software.
    +
    +PERMISSION & CONDITIONS
    +Permission is hereby granted, free of charge, to any person obtaining
    +a copy of the Font Software, to use, study, copy, merge, embed, modify,
    +redistribute, and sell modified and unmodified copies of the Font
    +Software, subject to the following conditions:
    +
    +1) Neither the Font Software nor any of its individual components,
    +in Original or Modified Versions, may be sold by itself.
    +
    +2) Original or Modified Versions of the Font Software may be bundled,
    +redistributed and/or sold with any software, provided that each copy
    +contains the above copyright notice and this license. These can be
    +included either as stand-alone text files, human-readable headers or
    +in the appropriate machine-readable metadata fields within text or
    +binary files as long as those fields can be easily viewed by the user.
    +
    +3) No Modified Version of the Font Software may use the Reserved Font
    +Name(s) unless explicit written permission is granted by the corresponding
    +Copyright Holder. This restriction only applies to the primary font name as
    +presented to the users.
    +
    +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
    +Software shall not be used to promote, endorse or advertise any
    +Modified Version, except to acknowledge the contribution(s) of the
    +Copyright Holder(s) and the Author(s) or with their explicit written
    +permission.
    +
    +5) The Font Software, modified or unmodified, in part or in whole,
    +must be distributed entirely under this license, and must not be
    +distributed under any other license. The requirement for fonts to
    +remain under this license does not apply to any document created
    +using the Font Software.
    +
    +TERMINATION
    +This license becomes null and void if any of the above conditions are
    +not met.
    +
    +DISCLAIMER
    +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
    +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
    +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
    +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
    +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
    +OTHER DEALINGS IN THE FONT SOFTWARE.
    +
    +--------------------------------------------------------------------------------
    +
    +# Code: MIT License (https://opensource.org/licenses/MIT)
    +
    +In the Font Awesome Free download, the MIT license applies to all non-font and
    +non-icon files.
    +
    +Copyright 2024 Fonticons, Inc.
    +
    +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.
    +
    +--------------------------------------------------------------------------------
    +
    +# Attribution
    +
    +Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font
    +Awesome Free files already contain embedded comments with sufficient
    +attribution, so you shouldn't need to do anything additional when using these
    +files normally.
    +
    +We've kept attribution comments terse, so we ask that you do not actively work
    +to remove them from files, especially code. They're a great way for folks to
    +learn about Font Awesome.
    +
    +--------------------------------------------------------------------------------
    +
    +# Brand Icons
    +
    +All brand icons are trademarks of their respective owners. The use of these
    +trademarks does not indicate endorsement of the trademark holder by Font
    +Awesome, nor vice versa. **Please do not use brand logos for any purpose except
    +to represent the company, product, or service to which they refer.**
    diff --git a/public/fonts/fa-brands-400.ttf b/public/fonts/fa-brands-400.ttf
    new file mode 100644
    index 00000000..c739a396
    Binary files /dev/null and b/public/fonts/fa-brands-400.ttf differ
    diff --git a/public/fonts/fa-brands-400.woff2 b/public/fonts/fa-brands-400.woff2
    new file mode 100644
    index 00000000..cb888623
    Binary files /dev/null and b/public/fonts/fa-brands-400.woff2 differ
    diff --git a/public/fonts/fa-regular-400.ttf b/public/fonts/fa-regular-400.ttf
    new file mode 100644
    index 00000000..31404094
    Binary files /dev/null and b/public/fonts/fa-regular-400.ttf differ
    diff --git a/public/fonts/fa-regular-400.woff2 b/public/fonts/fa-regular-400.woff2
    new file mode 100644
    index 00000000..fc0a2168
    Binary files /dev/null and b/public/fonts/fa-regular-400.woff2 differ
    diff --git a/public/fonts/fa-solid-900.ttf b/public/fonts/fa-solid-900.ttf
    new file mode 100644
    index 00000000..f3b468e5
    Binary files /dev/null and b/public/fonts/fa-solid-900.ttf differ
    diff --git a/public/fonts/fa-solid-900.woff2 b/public/fonts/fa-solid-900.woff2
    new file mode 100644
    index 00000000..42eaaa69
    Binary files /dev/null and b/public/fonts/fa-solid-900.woff2 differ
    diff --git a/public/images/acr-403-02.png b/public/images/acr-403-02.png
    new file mode 100644
    index 00000000..284f1d92
    Binary files /dev/null and b/public/images/acr-403-02.png differ
    diff --git a/public/images/acr-403.png b/public/images/acr-403.png
    new file mode 100644
    index 00000000..0202193d
    Binary files /dev/null and b/public/images/acr-403.png differ
    diff --git a/public/index.html b/public/index.html
    index 0da0e6ad..74d80833 100644
    --- a/public/index.html
    +++ b/public/index.html
    @@ -1,1046 +1,136 @@
    -
    +
    +
     
    -
    -
     
    -	
    -    
    -        
    -
    -
    -
    -
    -
    -GeekyRyan
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -    
    -
    -
    -
    -
    -
    -    
    -    
    -        
    -    
    -    
    -
    -    
    -        
    -    
    -
    -
    -
    -
    -
    -    
    -
    -    
    -
    -
    -
    +  
    +  GeekyRyan
    +  
    +  
    +  
     
    +  
    +  
    +  
     
    -    
    -    
    -        
    -    
    -    
    +  
    +  
    +  
     
    -    
    -        
    -    
    +  
    +  
    +  
    +  
    +  
    +  
     
    +  
     
    +  
    +  
    +  
     
    +  
     
    +  
     
    +  
    +  
    +  
     
    +  
    +  
     
    -
    -
    -
    -
    +  
    +  
     
    +  
     
    -
    -
    -
    -
    -
    -
    -    
    -        
    -        
    -            
    -        
    -    
    -    
    -        
    -    
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -    
    +  
     
    -
    -    Skip to main content
    -    
    -
    - -
    -

    - GeekyRyan -

    - -
    - -
    -
    - -
    - -
    - -
    - - -
    -
    -
    -

    Using try/catch/finally Blocks in PowerShell

    -
    - -
    - - -
    - Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it’s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we’ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn’t crash when the unexpected occurs. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Golang: When Identical Strings are Not Equal

    -
    - -
    - - -
    - This will be a quick and dirty post, so please forgive any spelling/grammar mistakes. -I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don’t write a ton of code at work (mostly just scripting/pipelines when I do), so I’m constantly working on something like this in my spare time. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Handling Graceful Shutdown in a .NET App Hosted in Kubernetes

    -
    - -
    - - -
    - I was recently involved with troubleshooting some API’s hosted in Kubernetes throwing http/502’s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Backup Synology NAS to Azure Storage

    -
    - -
    - - -
    - I’m not really a fan of photography. I don’t particularly enjoy the intracies of tuning a high-end DSLR camera. Nor am I a fan of being out in nature to photograph a fall sunrise (though, that does sound peaceful). However, I do take a lot of pictures with my phone (currently, a Pixel 6). Moreso now that I am a new father. I am protective of these photos. So much that I sync them automatically from my phone to two cloud storage providers. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Building a Golang App with Github Actions

    -
    - -
    - - -
    - In this article, we’ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app written in any language though. We’ll cover the following: -What are github actions? Setting up the workflow to build, test, and deploy a binary Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Chaining YAML Pipelines in Azure Devops

    -
    - -
    - - -
    - In this article, we’ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to figure this out. -Our two pipelines will exist in the same repository. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Update Azure Devops SPN Secret

    -
    - -
    - - -
    - If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal. -In this article, I’ll show you two methods for updating a secret for a service principal prior to expiration. -Update the secret via the Azure Devops Portal: Go to “Service Connections” in the Azure Devops portal Find the SPN you want to update, then click “Manage Service Principal” Then on the service principal page, click Certificates & Secrets Create a “New Client Secret”, take note of the value Delete the ‘old’ secret Return to the Service Connection in the Azure Devops portal Click Edit - click the verify button. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Use “replace” in go.mod to Point to a Local Module

    -
    - -
    - - -
    - If you want to the local version of a dependency in Go rather than one in a remote repository, use the replace keyword. -The replace line goes above your require statements, like so: -module github.com/rnemeth90/foo replace github.com/rnemeth90/bar => /Users/rnemeth90/Projects/bar require ( github.com/rnemeth90/bar v1.0.0 ) Now when you compile this module go build or go install, it will use your local code rather than the remote dependency. -According to the docs, you do need to make sure that the code you’re pointing to also has a go. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Powershell for Devops - Querying REST APIs with Powershell

    -
    - -
    - - -
    - This will be a short post on querying REST APIs with Powershell. -It’s hard to argue that REST APIs are the predominant technology for interacting with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) product without having to go through the exercise of a more complicated integration. REST APIs communicate in a common format, typically JSON. However, most will allow us to choose the response format by specifying an option in the ‘Accept’ header. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Reading Json Files with Go

    -
    - -
    - - -
    - JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting with it, and most public APIs accept JSON in HTTP requests. -In this post, we’ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the JSON data within the file into a memory structure. -
    - - -
    - Read more -
    - - - - - - - - - -
    - - - - - - - -
    - - -
    - -
    - - - - - -

    - - Ryan Nemeth - - - / - - - - - - -

    -
    - - -
    +
    +
    +
    +
    + avatar +
    + +

    Ryan Nemeth

    + +

    Full Stack DevOps Engineer

    + + +
    +
    +
    + +
    +
    + © 2012 - 2024 Ryan Nemeth · Powered by + Hugo & + Coder. +
    +
    + + + + diff --git a/public/index.xml b/public/index.xml index 7e877436..9f1f165a 100644 --- a/public/index.xml +++ b/public/index.xml @@ -2,3585 +2,564 @@ GeekyRyan - https://rnemeth90.github.io/ - GeekyRyan - Hugo -- gohugo.io - en-us - Tue, 15 Aug 2023 00:00:00 +0000 - - - - + http://localhost:1313/ + Recent content on GeekyRyan + Hugo + en + Sat, 29 Jun 2024 00:00:00 +0000 + + + Mounting Multiple Kubernetes Secrets into One Directory + http://localhost:1313/posts/2024-06-29-mount-multiple-kubernetes-secrets-into-one-directory/ + Sat, 29 Jun 2024 00:00:00 +0000 + http://localhost:1313/posts/2024-06-29-mount-multiple-kubernetes-secrets-into-one-directory/ + Introduction Link to heading Combining multiple Kubernetes secrets into a single directory can streamline secret management in your applications. This guide walks you through the process of achieving this in Kubernetes, ensuring efficient and organized secret management. Creating Secrets Link to heading First, create your secrets using the kubectl create secret command: kubectl create secret generic secret-one --from-literal=key1=value1 kubectl create secret generic secret-two --from-literal=key2=value2 Each secret can contain multiple key-value pairs, and you can add more secrets as needed. + + + Detecting MIME Types in Go + http://localhost:1313/posts/2024-03-27-golang-detect-file-type/ + Wed, 27 Mar 2024 00:00:00 +0000 + http://localhost:1313/posts/2024-03-27-golang-detect-file-type/ + Introduction Link to heading Knowing the type of a file you&rsquo;re working with is not just a matter of curiosity — it&rsquo;s often a necessity. This is especially true when you&rsquo;re deciding whether or not a particular operation can be carried out on that file. Go, with its comprehensive standard library, offers a straightforward approach to identifying a file&rsquo;s MIME type, ensuring that developers have the tools they need to make informed decisions about file manipulation. + + + Validating URLs with Go + http://localhost:1313/posts/2023-12-12-golang-url-validation/ + Tue, 19 Dec 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-12-12-golang-url-validation/ + Introduction Link to heading In this post, we&rsquo;ll take a quick look at URL validation using Golang. It&rsquo;s common to implement URL validation as a task within a HTTP request pipeline, typically as middleware. There are many different definitions of &ldquo;validation&rdquo;. For the purpose of this article, we will simply validate that a URL conforms to a particular text pattern. I often see people (mistakenly) use URL and URI interchangeably. + + + Nginx Ingress Response Header Size - A Cautionary Tale + http://localhost:1313/posts/2023-12-04-nginx-ingress-resp-header-size/ + Mon, 11 Dec 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-12-04-nginx-ingress-resp-header-size/ + This will be a short post about a recent issue I encountered when using Nginx as a Kubernetes ingress. Though, this could also be encountered when using Nginx as a reverse proxy as well. The two definitions are functionally similar. We recently had a client call in complaining of our application returning random 502s (Bad Gateway). After some investigation and the common finger-pointing, I found this entry in the logs of our ingress controllers: + + + Exploring Netcat + http://localhost:1313/posts/2023-11-27-netcat/ + Mon, 27 Nov 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-11-27-netcat/ + Introduction Link to heading Netcat is a versatile networking utility that can be used for a wide range of tasks. It has often been referred to as the &ldquo;network swiss-army knife&rdquo;. Netcat was first released in the mid-90s, and I personally find it ironic to be blogging about it in 2023! But I feel like it is a somewhat cryptic tool, and new engineers or college graduates may not be familiar. + Using try/catch/finally Blocks in PowerShell - https://rnemeth90.github.io/posts/2023-08-15-powershell-try-catch/ + http://localhost:1313/posts/2023-08-15-powershell-try-catch/ Tue, 15 Aug 2023 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2023-08-15-powershell-try-catch/ - <p>Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it&rsquo;s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we&rsquo;ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn&rsquo;t crash when the unexpected occurs. We&rsquo;ll then cover the differences in terminating and non-terminating errors and why you should take these into consideration when implementing error handling.</p> -<h2 id="the-try-block" >The Try Block -<span> - <a href="#the-try-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The Try block is where you place the code that might generate an error. Think of it as a protective bubble around your potentially troublesome code. If an error occurs within the Try block, PowerShell will immediately jump to the corresponding Catch block.</p> -<p>Here&rsquo;s a simple example:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><h2 id="the-catch-block" >The Catch Block -<span> - <a href="#the-catch-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The Catch block is where you can handle the error. PowerShell provides you with a special variable $_ that contains information about the error. You can use this variable to display error messages or even take corrective actions.</p> -<p>In the example above, we&rsquo;re capturing the error generated by attempting to retrieve a nonexistent file. The $_ variable holds the error message, which we&rsquo;re displaying using Write-Host.</p> -<h2 id="the-finally-block" >The Finally Block -<span> - <a href="#the-finally-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Now, let&rsquo;s talk about the unsung hero – the Finally block. This block is executed regardless of whether an error occurred or not. It&rsquo;s where you can place cleanup code that ensures your script leaves no trace behind, even in the face of adversity. Some tasks that are commonly done in the finally block are closing database connections, removing temp files, etc. The finally block is completely optional.</p> -<pre tabindex="0"><code> -try { - # Code that might generate an error - # ... -} -catch { - # Code to handle the error - # ... -} -finally { - # Cleanup code here - # ... -} -</code></pre><h2 id="terminatingnon-terminating-errors" >Terminating/non-terminating Errors -<span> - <a href="#terminatingnon-terminating-errors"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>non-terminating errors are any error that will not stop the execution of your script. Most cmdlets in PowerShell are non-terminating. They may output an error, but your script will continue to run. These kinds of errors cannot be caught with a catch block by default. The reason for this is the default <code>ErrorAction</code> in your PowerShell profile, which is set to <code>Continue</code>.</p> -<pre tabindex="0"><code># To show your default error action type -$ErrorActionPreference -</code></pre><p>Let&rsquo;s go back and look at our first example:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><p>If you took the time to run this code, you may have noticed that the <code>Write-Host</code> cmdlet in the <code>catch</code> block was never ran. Why did we get a red error message in our PowerShell console, rather than the text <code>An error occurred: ...</code>? The reason is that the non-existing path isn&rsquo;t a terminating error, and the default <code>ErrorAction</code> is <code>Continue</code>. To catch the error, you will need to change the <code>ErrorAction</code> in your PowerShell console to <code>Stop</code>. This can be done in multiple ways. You can add <code>-ErrorAction Stop</code> to the cmdlet, like this:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -ErrorAction Stop -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><p>Or you can change the <code>ErrorActionPreference</code> for the entire script, by adding this to the top of the script:</p> -<pre tabindex="0"><code>$ErrorActionPreference = &#34;Stop&#34; -</code></pre><h2 id="exceptions" >Exceptions -<span> - <a href="#exceptions"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>If you have ever worked with exceptions in C# you can skip this section. In the previous examples, we used simple <code>catch</code> blocks that will catch <em>any</em> error. This is a good start, but we can do better. PowerShell allows you to catch individual exceptions based on the exception type, similar to how C# handles catching exceptions.</p> -<p>Let&rsquo;s look at an example:</p> -<pre tabindex="0"><code>try { - # Attempt to open a non-existent file - $file = Get-Content -Path &#34;NonexistentFile.txt&#34; -} -catch [System.IO.FileNotFoundException] { - Write-Host &#34;Caught a FileNotFoundException: $_&#34; -} -catch { - Write-Host &#34;Caught an exception: $_&#34; -} -</code></pre><p>We now have two <code>catch</code> blocks. If we encounter an exception of type <code>System.IO.FileNotFoundException</code>, the first <code>catch</code> block will catch the exception and handle it accordingly. The second <code>catch</code> block will handle any other generic error.</p> -<h2 id="conclusion" >Conclusion -<span> - <a href="#conclusion"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Error handling might seem daunting at first, but with the power of Try-Catch-Finally blocks at your fingertips, you&rsquo;re well-equipped to handle errors gracefully and ensure the resilience of your PowerShell scripts. Remember, every error is an opportunity to refine your skills and make your scripts more robust.</p> -<p>Thanks for reading!</p> -<p>Official Microsoft Documentation for Try-Catch-Finally in PowerShell: -<a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-7.3">about_try_catch_finally</a></p> - - - + http://localhost:1313/posts/2023-08-15-powershell-try-catch/ + Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it&rsquo;s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we&rsquo;ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn&rsquo;t crash when the unexpected occurs. + Golang: When Identical Strings are Not Equal - https://rnemeth90.github.io/posts/2023-01-24-golang-strings-not-equal/ + http://localhost:1313/posts/2023-01-24-golang-strings-not-equal/ Tue, 24 Jan 2023 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2023-01-24-golang-strings-not-equal/ - <p><em>This will be a quick and dirty post, so please forgive any spelling/grammar mistakes.</em></p> -<p>I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don&rsquo;t write a ton of code at work (mostly just scripting/pipelines when I do), so I&rsquo;m constantly working on something like this in my spare time. Anyway, I was writing this app, got everything working like I wanted it to. I then wrote some of the tests and was iterating over them. I noticed the <code>ListTasks</code> test was failing:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TestAddTask</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">task</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;test task number 1&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Getwd</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmdPath</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">binaryName</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;AddNewTask&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-add&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">Run</span>(); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// failing test -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;ListTasks&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-list&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">out</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">CombinedOutput</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">expected</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;[ ] 1: %s&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Compare</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#a6e22e">expected</span>) <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;got %v, expected %v\n&#34;</span>, <span style="color:#a6e22e">out</span>, []byte(<span style="color:#a6e22e">expected</span>)) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Seems strange, considering the strings appear to be equivalent in the output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span> main_test.go:82: got <span style="color:#f92672">[</span> <span style="color:#f92672">]</span> 1: test task number <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> , expected <span style="color:#f92672">[</span> <span style="color:#f92672">]</span> 1: test task number <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>--- FAIL: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- FAIL: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>FAIL -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>exit status <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>FAIL github.com/rnemeth90/todo/cmd/todo 0.105s -</span></span></code></pre></div><p>What could be happening? After banging my head on the desk a few times, a revelation came to me&hellip;</p> -<p>In Go, strings are simply slices of bytes. I decided to print out each string as a byte array:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span> main_test.go:80: got <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">10</span> 10<span style="color:#f92672">]</span>, expected <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> 49<span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span>--- FAIL: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- FAIL: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>FAIL -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>exit status <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>FAIL github.com/rnemeth90/todo/cmd/todo 0.144s -</span></span></code></pre></div><p>Let&rsquo;s take a closer look at the byte arrays from the test output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>got <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">10</span> 10<span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span>expected <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> 49<span style="color:#f92672">]</span> -</span></span></code></pre></div><p>We can see the byte array returned from <code>cmd.CombinedOutput()</code> has some additional bytes in it at the end (32,10,10). What exactly are 32, 10, and 10? To figure this out, I went over to the go playground: <a href="https://go.dev/play/">https://go.dev/play/</a>.</p> -<p>Let&rsquo;s see what happens when we create a byte array with a single number and print it out as a string to the console:</p> -<p><a href="https://rnemeth90.github.io/images/golang-strings-not-equal-01.png"><img src="https://rnemeth90.github.io/images/golang-strings-not-equal-01.png" alt=""></a></p> -<p>Interesting, we can see that <code>m</code> was output to the console. So what do our mysterious additional characters in our test result represent? Let&rsquo;s see:</p> -<p><a href="https://rnemeth90.github.io/images/golang-strings-not-equal-02.png"><img src="https://rnemeth90.github.io/images/golang-strings-not-equal-02.png" alt=""></a></p> -<p>It&rsquo;s hard to tell from the output, but if you look in the results pane, you&rsquo;ll see a space and two new lines. So <code>32</code> represents a space, and <code>10</code> represents a new line!</p> -<p>You can play with this code yourself: <a href="https://go.dev/play/p/fGUIxJM6KnV">https://go.dev/play/p/fGUIxJM6KnV</a></p> -<p>Ok, so let&rsquo;s fix our failing test:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TestAddTask</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">task</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;test task number 1&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Getwd</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmdPath</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">binaryName</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;AddNewTask&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-add&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">Run</span>(); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;ListTasks&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-list&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">out</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">CombinedOutput</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// add this line -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">out</span> = []byte(<span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">TrimSuffix</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#e6db74">&#34; \n\n&#34;</span>)) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">expected</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;[ ] 1: %s&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Compare</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#a6e22e">expected</span>) <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;got %v, expected %v\n&#34;</span>, <span style="color:#a6e22e">out</span>, []byte(<span style="color:#a6e22e">expected</span>)) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>The <code>strings</code> package has a <code>TrimSuffix</code> function that is useful for trimming bits off the end of a string. In the code above, you can see that we added <code>out = []byte(strings.TrimSuffix(string(out), &quot; \n\n&quot;))</code>, which will trim off the space (character 32) and the two new lines (character 10). Now when we run our integration test, it passes:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span>--- PASS: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>PASS -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>ok github.com/rnemeth90/todo/cmd/todo 0.106s -</span></span></code></pre></div> - - + http://localhost:1313/posts/2023-01-24-golang-strings-not-equal/ + This will be a quick and dirty post, so please forgive any spelling/grammar mistakes. I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don&rsquo;t write a ton of code at work (mostly just scripting/pipelines when I do), so I&rsquo;m constantly working on something like this in my spare time. + Handling Graceful Shutdown in a .NET App Hosted in Kubernetes - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ Wed, 28 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ - <p>I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. It was actually a combination of these blogs (and the resolutions posted) that ended up resolving our issue.</p> -<h3 id="so-what-was-actually-causing-the-502s" >So what was actually causing the 502&rsquo;s? -<span> - <a href="#so-what-was-actually-causing-the-502s"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h3><p>As stated, these APIs are hosted in Kubernetes. They are written primarily in c# (.NET Framework) and hosted in Windows Server Core containers. The pods are load balanced using a service, and we have an Nginx ingress on top of the service. Nothing fancy, just a typical setup that you may have seen or even built yourself. We implement automatic scaling for our replica sets using a standard Kubernetes-native HPA or Keda, depending on the app. We have autoscale rules defined for the pods. Our clusters are hosted in Azure Kubernetes Service, and we autoscale our node pools. So, there are several layers of scaling happening in our clusters at any given time. Occasionally, when a pod was handling a client request, Kubelet or a controller would come along and scale the pod in. We were initially under the belief that the <code>terminationGracePeriodSeconds</code> value within our deployment would allow the pod to continue running for the defined number of seconds. However, we were mistaken. This value tells Kubernetes to allow the application running within the pod some time to clean up. It does <em>not</em> tell the app to continue running for the defined number of seconds after it receives a sigterm signal. This logic actually needs to be implemented within the application itself, or with a prestop hook. The prestop method is <a href="https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/">well documented</a>, so I will not cover it here.</p> -<p>To implement this in a .NET Framework app running in Windows, you need to add this registry key to your container.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">RUN</span> reg add hklm<span style="color:#ae81ff">\s</span>ystem<span style="color:#ae81ff">\c</span>urrentcontrolset<span style="color:#ae81ff">\c</span>ontrol /v WaitToKillServiceTimeout /t REG_SZ /d <span style="color:#ae81ff">60000</span> /f<span style="color:#960050;background-color:#1e0010"> -</span></span></span></code></pre></div><p>This value tells Windows to wait a number of milliseconds before shutting down Normally, Windows only waits for 5 seconds (default) before shutting down any &lsquo;background&rsquo; processes. Windows forcibly shuts down processes after this period of time.</p> -<p>Next, in the startup class, we&rsquo;ll add the following code. I have added inline comments to explain.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c#" data-lang="c#"><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">namespace</span> MyApp.APIConsoleHost -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Program</span> -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Register the SetConsoleCtrlHandler function in kernel32.dll in the -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> application to capture CTRL_SHUTDOWN_EVENT events for resource reclamation -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e"> [DllImport(&#34;Kernel32&#34;)]</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">extern</span> <span style="color:#66d9ef">bool</span> SetConsoleCtrlHandler(HandlerRoutine handler, <span style="color:#66d9ef">bool</span> <span style="color:#66d9ef">add</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Define a delegate for our handler routine</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">delegate</span> <span style="color:#66d9ef">bool</span> HandlerRoutine(CtrlTypes ctrlType); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">volatile</span> ManualResetEvent _exitEvent = <span style="color:#66d9ef">new</span> ManualResetEvent(<span style="color:#66d9ef">false</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> HandlerRoutine _handler; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Define the event types that we want to handle when the application receives a SIGTERM -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_C_EVENT = 0, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_BREAK_EVENT = 1, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_CLOSE_EVENT = 2, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_LOGOFF_EVENT = 5, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_SHUTDOWN_EVENT = 6 -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">enum</span> CtrlTypes -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> CTRL_SHUTDOWN_EVENT = <span style="color:#ae81ff">6</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Here we are defining how we want to handle the shutdown -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We get a timeout value from an env variable named APP_SHUTDOWN_TIMEOUT -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> If that env variable is not found, we default to 60 seconds. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We then switch on our CtrlTypes enum and handle each value accordingly, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then return true. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">bool</span> ConsoleCtrlCheck(CtrlTypes ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> timeout = ConfigurationManager.AppSettings[<span style="color:#e6db74">&#34;APP_SHUTDOWN_TIMEOUT&#34;</span>]; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> (<span style="color:#66d9ef">string</span>.IsNullOrEmpty(timeout)) { timeout = <span style="color:#e6db74">&#34;60&#34;</span>; } -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">int</span> counter = <span style="color:#66d9ef">int</span>.Parse(timeout); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">switch</span> (ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> CtrlTypes.CTRL_SHUTDOWN_EVENT: -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] CTRL_SHUTDOWN received&#34;</span>); -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] Web Server is stopping in {counter} seconds&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">while</span> (counter &gt; <span style="color:#ae81ff">0</span>) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> Thread.Sleep(TimeSpan.FromSeconds(<span style="color:#ae81ff">1</span>)); -</span></span><span style="display:flex;"><span> counter--; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.Set(); -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span>; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span>: -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">false</span>; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Our main method is pretty standard. However, we first register a new handler (_handler), -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then pass it to to the SetConsoleCtrlHandler() method we imported from Kernel32.dll. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> The only other &#39;unique&#39; thing is the _exitEvent.WaitOne(); call defined at the bottom of main(). -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> This is necessary so that main does not immediately exit, and wait&#39;s for a signal. We defined a -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> property for this _exitEvent of type ManualResetEvent at the top of this class file. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> Main(<span style="color:#66d9ef">string</span>[] args) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> _handler += <span style="color:#66d9ef">new</span> HandlerRoutine(ConsoleCtrlCheck); -</span></span><span style="display:flex;"><span> SetConsoleCtrlHandler(_handler, <span style="color:#66d9ef">true</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = BuildStartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> WebApp.Start&lt;SelfHostStartup&gt;(startOptions); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">&#34;Press CTRL+C to stop it&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.WaitOne(); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> StartOptions BuildStartOptions() -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = <span style="color:#66d9ef">new</span> StartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted start options</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> startOptions; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>To prevent the HandlerRoutine instance from being recycled by the GC before the program exits, the HandlerRoutine must be static (as seen in the above example). This is important because if the handlerroutine is recycled before the application is finished, it will throw an error, as shown here:</p> -<pre tabindex="0"><code>A callback was made on a garbage collected delegate of type &#39;Program+HandlerRoutine::Invoke&#39;. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called. -</code></pre> - - + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. + Backup Synology NAS to Azure Storage - https://rnemeth90.github.io/posts/2022-12-25-synology-backup-to-cloud/ + http://localhost:1313/posts/2022-12-25-synology-backup-to-cloud/ Tue, 27 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-25-synology-backup-to-cloud/ - <p>I&rsquo;m not really a fan of photography. I don&rsquo;t particularly enjoy the intracies of tuning a high-end DSLR camera. Nor am I a fan of being out in nature to photograph a fall sunrise (though, that does sound peaceful). However, I do take a lot of pictures with my phone (currently, a Pixel 6). Moreso now that I am a new father. I am protective of these photos. So much that I sync them automatically from my phone to two cloud storage providers. I thought the other day, how painful it would be for either of these cloud storage providers to go offline. Though unlikely, anything is possible, right?</p> -<p>So, like any good engineer, I started looking for a solution for this concern. I have 2 Synology NAS devices here at my home. Calling a Synology a NAS is almost an insult. They are much more than that. Though they specialize in storage, they provide a plethora of apps that extend the functionality of the device. A Synology device can provide storage, email, DNS, media, etc. services though OEM and third-party apps. A single device can also link up with other devices to form a highly-available mesh of Synology services. Pretty neat for just a little black desktop box! Anyway, I&rsquo;m not a Synology salesman, so let&rsquo;s get back on track&hellip;</p> -<p>I wanted to be able to have a local copy of all of my photos (and other files) that are currently synced to the cloud. I then wanted to backup this local copy to another remote location (something like a 3-2-1 backup architecture, but not really&hellip;). Synology provides an app called Cloud Sync that can be used to sync files from a cloud storage provider like Google Photos/Drive or Microsoft OneDrive to a local device. They also provide another app called Hyper Backup that can be used to backup local files to remote storage, like an Azure Storage Account or Amazon S3 Bucket. By now, you probably get where this is going.</p> -<p>I&rsquo;m going to configure Cloud Sync to pull files down to my Synology and then use Hyper Backup to push a weekly backup to Azure Blob Storage. Let&rsquo;s dive in! -If you&rsquo;re following along, you&rsquo;ll need to install both of these apps. They are available via One-Click install in the Synology Package Center, so I won&rsquo;t cover the installation process. The setup is extremely simple as well, but I&rsquo;ll go over it just because.</p> -<p>We&rsquo;ll first setup Cloud Sync. Open Cloud Sync and click the &lsquo;+&rsquo; symbol to add a new account.</p> -<p>For my purposes, I&rsquo;m going to choose Microsoft OneDrive:</p> -<p><a href="https://rnemeth90.github.io/images/synology-cloud-sync-01.png"><img src="https://rnemeth90.github.io/images/synology-cloud-sync-01.png" alt=""></a></p> -<p>When prompted to authenticate, login to your OneDrive account. Then, configure the sync settings. You can create a name for the connection, add a local path in which to sync your files to, choose which remote folders/files to sync, the sync direction, a schedule, etc.</p> -<p><a href="https://rnemeth90.github.io/images/synology-cloud-sync-02.png"><img src="https://rnemeth90.github.io/images/synology-cloud-sync-02.png" alt=""></a></p> -<p>Click Next, and then finish the wizard. Simple.</p> -<p>Depending on the amount of files you have, you&rsquo;ll need to allow some time for your files to sync.</p> -<p>Now, we&rsquo;ll setup Hyper Backup to backup the files you sync&rsquo;d locally to remote storage. As stated previously, I&rsquo;ll be backing up my files to Azure Blob Storage. I have already created the Storage Account in Azure, and will not be covering that in this article.</p> -<p>Open Hyper Backup and click the &lsquo;+&rsquo; symbol in the lower left corner, and then click &lsquo;Data Backup Task&rsquo;. Then, choose &lsquo;Microsoft Azure&rsquo;:</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-01.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-01.png" alt=""></a> -<a href="https://rnemeth90.github.io/images/synology-hyper-backup-02.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-02.png" alt=""></a></p> -<p>On the next page, enter in your Storage Account info and then click Next. You can then choose which local folders on your Synology to backup:</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-03.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-03.png" alt=""></a></p> -<p>Click next and choose to backup application settings:</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-04.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-04.png" alt=""></a></p> -<p>On this page, we can configure the backup settings. Name the task, and configure your notification settings, schedule, compression, and encryption.</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-05.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-05.png" alt=""></a></p> -<p>On the last page, we configure our backup rotation settings. I am going to keep 31 days of backups, starting from the oldest backup. This means that at any given time I will have 31 days worth of backups in the storage account.</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-06.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-06.png" alt=""></a></p> -<p>That&rsquo;s all for configuring the backups! Very simple. Depending on how much data you have and your ISP, it may take a while to backup your files. If you configured notifications, you should receive a notification once the job is complete.</p> - - - + http://localhost:1313/posts/2022-12-25-synology-backup-to-cloud/ + I&rsquo;m not really a fan of photography. I don&rsquo;t particularly enjoy the intracies of tuning a high-end DSLR camera. Nor am I a fan of being out in nature to photograph a fall sunrise (though, that does sound peaceful). However, I do take a lot of pictures with my phone (currently, a Pixel 6). Moreso now that I am a new father. I am protective of these photos. So much that I sync them automatically from my phone to two cloud storage providers. + Building a Golang App with Github Actions - https://rnemeth90.github.io/posts/2022-12-24-gh-actions-copy/ + http://localhost:1313/posts/2022-12-24-gh-actions-copy/ Fri, 23 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-24-gh-actions-copy/ - <p>In this article, we&rsquo;ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app -written in any language though. We&rsquo;ll cover the following:</p> -<ol> -<li>What are github actions?</li> -<li>Setting up the workflow to build, test, and deploy a binary</li> -</ol> -<p>Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. They are powerful and I suggest you read more at the <a href="https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions">Official Docs</a></p> -<p>To get started, we&rsquo;ll need a golang app to build. You can use my example <a href="https://github.com/rnemeth90/golang-github-action-example">here</a> if you do not have your own.</p> -<p>The process is relatively simple. At the root of your repo, create the following directories:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>mkdir -p .github/workflows -</span></span></code></pre></div><p>Then create a yaml file (you can name it anything you want) with the content below:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">name</span>: <span style="color:#ae81ff">build-release-binary</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">run-name</span>: <span style="color:#ae81ff">Create Github Release for GoLang binary</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># anytime we push to our repo with a tag starting with the</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># letter &#39;r&#39;, we run the build</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">on</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">push</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tags</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#e6db74">&#39;r*&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">jobs</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">build</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">runs-on</span>: <span style="color:#ae81ff">ubuntu-22.04</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">permissions</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">contents</span>: <span style="color:#ae81ff">write</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># checkout our github repo to the build agent</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/checkout@v3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">fetch-depth</span>: <span style="color:#ae81ff">0</span> <span style="color:#75715e"># get all tags, needed to get git log</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">ref</span>: <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Setup the Go environment</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">setup Go Lang</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">id</span>: <span style="color:#ae81ff">build</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/setup-go@v3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">go-version</span>: <span style="color:#e6db74">&#39;^1.19.2&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Build our application</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go version -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> cd src -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [ ! -e *.mod ]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go mod init ${GITHUB_REPOSITORY} -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go mod tidy -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go build -ldflags &#34;-X main.Version=${GITHUB_REF_NAME} -X main.BuiltBy=github-actions&#34; main.go -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> execFile=$(find . -type f -executable)</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Output more values for debugging</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git version</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git branch</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git tag</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># tag our release</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">get semantic tag version and release notes from commit messages</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">id</span>: <span style="color:#ae81ff">tag</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">run</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> currentTag=${GITHUB_REF_NAME} -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> major_minor=$(echo &#34;$currentTag&#34; | cut -d&#39;.&#39; -f1-2) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> patch=$(echo &#34;$currentTag&#34; | cut -d&#39;.&#39; -f3) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> # avoid empty patch number -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> [ -n &#34;$patch&#34; ] &amp;&amp; ((patch--)) || patch=&#34;.x&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> previousTag=&#34;${major_minor}.${patch}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;&#34; &gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if git tag | grep $previousTag ; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git log -q ${currentTag}...${previousTag} --pretty=&#34;- %s&#34; -q --no-color &gt;&gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> else -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git log --pretty=&#34;- %s&#34; -q --no-color &gt;&gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> line_count=$(cat body.log | wc -l) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;currentTag=$currentTag&#34; &gt;&gt; $GITHUB_OUTPUT -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;previousTag=$previousTag&#34; &gt;&gt; $GITHUB_OUTPUT -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;line_count=$line_count&#34; &gt;&gt; $GITHUB_OUTPUT</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># create Github release with release note from file and binary asset attached</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">ncipollo/release-action@v1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">${{ env.GITHUB_REF_NAME }}</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tag</span>: <span style="color:#ae81ff">${{ env.GITHUB_REF_NAME }}</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">artifacts</span>: <span style="color:#e6db74">&#34;src/main&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">bodyFile</span>: <span style="color:#e6db74">&#34;body.log&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">token</span>: <span style="color:#ae81ff">${{ secrets.GITHUB_TOKEN }}</span> -</span></span></code></pre></div><p>Each step within this workflow starts with a hyphen. The steps are well-commented, so I will not explain them further. Once you have this file in your repo, push it to github. Then navigate to the Actions tab in your repository and you should see your workflow on the left hand side of the screen.</p> -<p><a href="https://rnemeth90.github.io/images/gh-actions-1.png"><img src="https://rnemeth90.github.io/images/gh-actions-1.png" alt=""></a></p> -<p>Now that we have our workflow setup, to get it run, all you need to do is tag and push your release to github. To do that, you can run the script in my repo <a href="https://github.com/rnemeth90/golang-github-action-example/blob/main/create_new_gh_release.sh">create_new_gh_release.sh</a> or simply run the following commands (be sure to change the tag as needed):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>newtag<span style="color:#f92672">=</span>r1.0.0 -</span></span><span style="display:flex;"><span>git tag $newtag <span style="color:#f92672">&amp;&amp;</span> git push origin $newtag -</span></span></code></pre></div><p>Now, go back to the Actions tab in your repo, and you should see the build running. Once it completes, go back to the Code tab in your github repo and you will see the release on the right hand side of the screen.</p> -<p><a href="https://rnemeth90.github.io/images/gh-actions-2.png"><img src="https://rnemeth90.github.io/images/gh-actions-2.png" alt=""></a></p> - - - + http://localhost:1313/posts/2022-12-24-gh-actions-copy/ + In this article, we&rsquo;ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app written in any language though. We&rsquo;ll cover the following: What are github actions? Setting up the workflow to build, test, and deploy a binary Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. + Chaining YAML Pipelines in Azure Devops - https://rnemeth90.github.io/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ + http://localhost:1313/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ Thu, 03 Nov 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ - <p>In this article, we&rsquo;ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. -Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to -figure this out.</p> -<p>Our two pipelines will exist in the same repository. We have a dependent-pipeline, that we only want to run once the source-pipeline is finished. This is useful if you have -some infrastructure you want to build, prior to deploying something to that infrastructure.</p> -<p>The process is actually quite simple. First, let&rsquo;s define our source pipeline:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># source-pipeline</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: <span style="color:#ae81ff">echo Hello, world!</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a one-line script&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo Add other tasks to build, test, and deploy your project. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo See https://aka.ms/yaml</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a multi-line script&#39;</span> -</span></span></code></pre></div><p>Nothing fancy here, just the build in template pipeline that Microsoft gives us for free when we create a &ldquo;Starter Pipeline&rdquo;.</p> -<p>Now, let&rsquo;s create another pipeline in the same repo that will be triggered when the pipeline above completes:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># dependent-pipeline</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">none</span> <span style="color:#75715e"># we want this pipeline to be triggered manually, not based on PR, etc.</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">pipelines</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">pipeline</span>: <span style="color:#ae81ff">source-pipeline</span> <span style="color:#75715e">#this can be anything</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">source</span>: <span style="color:#e6db74">&#39;source-pipeline&#39;</span> <span style="color:#75715e">#this needs to be the name of the &#39;source&#39; pipeline</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">trigger</span>: <span style="color:#66d9ef">true</span> <span style="color:#75715e"># Run dependent-pipeline pipeline when any run of security-lib-ci completes</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: <span style="color:#ae81ff">echo Hello, world!</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a one-line script&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo Add other tasks to build, test, and deploy your project. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo See https://aka.ms/yaml</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a multi-line script&#39;</span> -</span></span></code></pre></div><p>The resources block above defines our dependency. You want to be sure to configure the trigger of the dependent pipeline appropriately as well.</p> -<p>There are several options for fine-tuning this process. See the office Microsoft documentation below:</p> -<p><a href="https://learn.microsoft.com/en-us/azure/devops/pipelines/process/pipeline-triggers?view=azure-devops">Link to the Microsoft Docs</a></p> - - - + http://localhost:1313/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ + In this article, we&rsquo;ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to figure this out. Our two pipelines will exist in the same repository. + Update Azure Devops SPN Secret - https://rnemeth90.github.io/posts/2022-09-12-update-azure-devops-spn-secret/ + http://localhost:1313/posts/2022-09-12-update-azure-devops-spn-secret/ Mon, 12 Sep 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-09-12-update-azure-devops-spn-secret/ - <p>If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal.</p> -<p>In this article, I&rsquo;ll show you two methods for updating a secret for a service principal prior to expiration.</p> -<h1 id="update-the-secret-via-the-azure-devops-portal" >Update the secret via the Azure Devops Portal: -<span> - <a href="#update-the-secret-via-the-azure-devops-portal"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h1><ul> -<li>Go to &ldquo;Service Connections&rdquo; in the Azure Devops portal</li> -<li>Find the SPN you want to update, then click &ldquo;Manage Service Principal&rdquo;</li> -<li>Then on the service principal page, click Certificates &amp; Secrets</li> -<li>Create a &ldquo;New Client Secret&rdquo;, take note of the value</li> -<li>Delete the &lsquo;old&rsquo; secret</li> -<li>Return to the Service Connection in the Azure Devops portal</li> -<li>Click Edit - click the verify button. It should tell you the client certificate has expired</li> -<li>Now you need to make an arbitrary change and save it. I just type a character in the optional description and save.</li> -<li>Now edit again and click verify, it will now pick up the new client secret and all is happy.</li> -<li>You can now remove whatever you added to the description.</li> -</ul> - - - + http://localhost:1313/posts/2022-09-12-update-azure-devops-spn-secret/ + If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal. In this article, I&rsquo;ll show you two methods for updating a secret for a service principal prior to expiration. Update the secret via the Azure Devops Portal: Link to heading Go to &ldquo;Service Connections&rdquo; in the Azure Devops portal Find the SPN you want to update, then click &ldquo;Manage Service Principal&rdquo; Then on the service principal page, click Certificates &amp; Secrets Create a &ldquo;New Client Secret&rdquo;, take note of the value Delete the &lsquo;old&rsquo; secret Return to the Service Connection in the Azure Devops portal Click Edit - click the verify button. + Use “replace” in go.mod to Point to a Local Module - https://rnemeth90.github.io/posts/2022-09-06-go-mod-replace-copy/ + http://localhost:1313/posts/2022-09-06-go-mod-replace-copy/ Tue, 06 Sep 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-09-06-go-mod-replace-copy/ - <p>If you want to the local version of a dependency in Go rather than one in a remote repository, use the <em>replace</em> keyword.</p> -<p>The replace line goes above your require statements, like so:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> module github.com/rnemeth90/foo -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> replace github.com/rnemeth90/bar <span style="color:#f92672">=</span>&gt; /Users/rnemeth90/Projects/bar -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> require <span style="color:#f92672">(</span> -</span></span><span style="display:flex;"><span> github.com/rnemeth90/bar v1.0.0 -</span></span><span style="display:flex;"><span> <span style="color:#f92672">)</span> -</span></span></code></pre></div><p>Now when you compile this module <em>go build</em> or <em>go install</em>, it will use your local code rather than the remote dependency.</p> -<p>According to the docs, you do need to make sure that the code you’re pointing to also has a <strong>go.mod</strong> file:</p> -<blockquote> -<p><strong>Note</strong>: if the right-hand side of a <code>replace</code> directive is a filesystem path, then the target must have a <code>go.mod</code> file at that location. If the <code>go.mod</code> file is not present, you can create one with <code>go mod init</code>.</p> -<p><a href="https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive">https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive</a></p> -</blockquote> -<p>You can also create this line from the command line using the <strong>go mod edit</strong> command.</p> -<pre><code>$ go mod edit -replace github.com/rnemeth90/bar=/Users/rnemeth90/Projects/bar -</code></pre> -<p>Following the <strong>-replace</strong> is first what you want to replace, then an equals sign, then what you’re replacing it with.</p> -<p>Hopefully this helps someone who was stuck with this like me 🙂</p> - - - + http://localhost:1313/posts/2022-09-06-go-mod-replace-copy/ + If you want to the local version of a dependency in Go rather than one in a remote repository, use the replace keyword. The replace line goes above your require statements, like so: module github.com/rnemeth90/foo replace github.com/rnemeth90/bar =&gt; /Users/rnemeth90/Projects/bar require ( github.com/rnemeth90/bar v1.0.0 ) Now when you compile this module go build or go install, it will use your local code rather than the remote dependency. According to the docs, you do need to make sure that the code you’re pointing to also has a go. + Powershell for Devops - Querying REST APIs with Powershell - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ Thu, 04 Aug 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ - <p>This will be a short post on querying REST APIs with Powershell.</p> -<p>It&rsquo;s hard to argue that REST APIs are the predominant technology for interacting -with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) -product without having to go through the exercise of a more complicated integration. REST APIs communicate -in a common format, typically JSON. However, most will allow us to choose the response format by specifying an -option in the &lsquo;Accept&rsquo; header. Most languages provide a native method for interacting with -REST APIs. This objective for this post is to show you how simple this is with Powershell.</p> -<p>To get started, we&rsquo;ll need a public API to interact with. I&rsquo;m going to use <a href="https://icanhazdadjoke.com/">https://icanhazdadjoke.com/</a>, because -there is no authentication and no rate-limiting (two concepts we will cover in another post).</p> -<p>Calling the API is extremely simple:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -</span></span></code></pre></div><p>However, this results in the content being returned as plain text. This isn&rsquo;t ideal.</p> -<p>Let&rsquo;s pass the &lsquo;Accept&rsquo; header to tell the API the format we are expecting to be returned:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers -</span></span></code></pre></div><p>Output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>[<span style="color:#ae81ff">15</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">04</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">34</span>] C:\..\..\rnemeth90.github.io on <span style="color:#960050;background-color:#1e0010"></span>main <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#ae81ff">+1</span> <span style="color:#960050;background-color:#1e0010">❯</span> Invoke-RestMethod -Uri $url -Method Get -Headers $headers -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>id joke status -</span></span><span style="display:flex;"><span>-- ---- ------ -</span></span><span style="display:flex;"><span>3LmyXvsPfqc I don<span style="color:#e6db74">&#39;t trust stairs. They&#39;</span>re always up to something. <span style="color:#ae81ff">200</span> -</span></span></code></pre></div><p>That looks a little better. For those of you familiar with Powershell, the output above probably -looks completely normal. But for those not-so-familiar with Powershell, or those expecting -more of a &lsquo;json-esk&rsquo; output, this may look a bit&hellip; weird.</p> -<p>Powershell is an object oriented language. <strong>Everything is an object</strong> in Powershell, even the response -of this request. What you see in the output is simply the properties of the object.</p> -<p>Luckily Powershell provides us with a cmdlet to convert an object into json (aptly named: ConvertTo-Json). We can use it like this:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers | ConvertTo-Json -</span></span></code></pre></div><p>Here we are piping the output from Invoke-RestMethod to ConvertTo-Json. Pretty neat!</p> -<p>Output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>[<span style="color:#ae81ff">15</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">04</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">35</span>] C:\..\..\rnemeth90.github.io on <span style="color:#960050;background-color:#1e0010"></span>main <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#ae81ff">+1</span> <span style="color:#960050;background-color:#1e0010">❯</span> Invoke-RestMethod -Uri $url -Method Get -Headers $headers | Convertto-json -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;id&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#e6db74">&#34;AAdFBXnGlyd&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;joke&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#e6db74">&#34;If you walk into a forest and cut down a tree, but the tree doesn&#39;t understand why you cut it down, do you think it&#39;s stumped?&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;status&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#ae81ff">200</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Now, that looks more normal.</p> -<p>There is much more we can do with Invoke-RestMethod. The &lsquo;Method&rsquo; parameter of this cmdlet accepts any of the common -HTTP methods (GET, PUT, PATCH, DELETE, POST, HEAD). You can also specify other headers and a body (using the -body parameter).</p> -<p>Both of these parameters accept dictionaries:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Host&#39;</span> = <span style="color:#e6db74">&#39;MyServer&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>$body = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Eat&#39;</span> = <span style="color:#e6db74">&#39;Pizza&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers -Body $body | ConvertTo-Json -</span></span></code></pre></div><p>Unfortunately I won&rsquo;t be able to show the other HTTP methods, as this API only supports GET requests. So that&rsquo;s all for now.</p> - - - + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ + This will be a short post on querying REST APIs with Powershell. It&rsquo;s hard to argue that REST APIs are the predominant technology for interacting with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) product without having to go through the exercise of a more complicated integration. REST APIs communicate in a common format, typically JSON. However, most will allow us to choose the response format by specifying an option in the &lsquo;Accept&rsquo; header. + Reading Json Files with Go - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ + http://localhost:1313/posts/2022-07-21-reading-json-files-with-go/ Thu, 21 Jul 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ - <p>JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting -with it, and most public APIs accept JSON in HTTP requests.</p> -<p>In this post, we&rsquo;ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the -JSON data within the file into a memory structure.</p> -<p>Let&rsquo;s assume we have the following JSON data representing an employee:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">1</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Steve&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Rogers&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Captain America&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Department&#34;</span>: <span style="color:#e6db74">&#34;Avengers&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>We need a way of representing this data in memory when decoding it from JSON. For this, we will need to create a struct:</p> -<p>We will build up our go module as we progress through the article</p> -<p>Let&rsquo;s start:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#75715e">// main.go -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> ( -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;encoding/json&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;fmt&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;io/ioutil&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;log&#34;</span> -</span></span><span style="display:flex;"><span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">// Hero represents an hero -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// ALL fields must be exportable! Otherwise the JSON parsing will fail. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Hero</span> <span style="color:#66d9ef">struct</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Id</span> <span style="color:#66d9ef">int</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">FirstName</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">LastName</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Alias</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Group</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() { -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Here we set the log prefix. When reading stack traces, this makes it easier to know -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// where a failure occurred. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">SetPrefix</span>(<span style="color:#e6db74">&#34;main(): &#34;</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// We first need to load the JSON file into memory -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">content</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">ioutil</span>.<span style="color:#a6e22e">ReadFile</span>(<span style="color:#e6db74">&#34;./heros.json&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#e6db74">&#34;Error opening the file: &#34;</span>, <span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Now we parse the JSON data into a memory structure. We know our JSON file will have more than one hero object, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// so we&#39;ll use make() to create a []Hero slice. Since go is a pass-by-value language, we will then use the address-of -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// operator (&amp;) to unmarshal our json data into the heros slice -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">heros</span> <span style="color:#f92672">:=</span> make([]<span style="color:#a6e22e">Hero</span>, <span style="color:#ae81ff">5</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">json</span>.<span style="color:#a6e22e">Unmarshal</span>(<span style="color:#a6e22e">content</span>, <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">heros</span>) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#e6db74">&#34;Error occurred during unmarshal: &#34;</span>, <span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// now we can read/interact with the data. We&#39;ll loop over the array -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// and print the values in memory -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; len(<span style="color:#a6e22e">heros</span>); <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">Id</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">FirstName</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">LastName</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">Group</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Create a file named employees.json with similar data:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>[ -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">1</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Steve&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Rogers&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Captain America&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;group&#34;</span>: <span style="color:#e6db74">&#34;Avengers&#34;</span> -</span></span><span style="display:flex;"><span> }, -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">2</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Clark&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Kent&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Superman&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;group&#34;</span>: <span style="color:#e6db74">&#34;Justice League&#34;</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>] -</span></span></code></pre></div><p>Now, we can run our main.go file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>11:40:47 ryan@xerxes json → go run main.go -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>Steve -</span></span><span style="display:flex;"><span>Rogers -</span></span><span style="display:flex;"><span>Avengers -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span>Clark -</span></span><span style="display:flex;"><span>Kent -</span></span><span style="display:flex;"><span>Justice League -</span></span><span style="display:flex;"><span>11:40:49 ryan@xerxes json -</span></span></code></pre></div><p>Pretty simple! That&rsquo;s why I love go. We accomplished all of this with ~50 lines of code. -Doing something similar in asp.net project would easily double that count and involve creating -multiple files! (nothing against asp.net or c#, I think c# is a great language and use it daily)</p> -<p>Now, &lsquo;go&rsquo; try this!</p> - - - + http://localhost:1313/posts/2022-07-21-reading-json-files-with-go/ + JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting with it, and most public APIs accept JSON in HTTP requests. In this post, we&rsquo;ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the JSON data within the file into a memory structure. + AKS Scale Down Mode - https://rnemeth90.github.io/posts/2022-07-19-aks-scale-down-mode/ + http://localhost:1313/posts/2022-07-19-aks-scale-down-mode/ Tue, 19 Jul 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-07-19-aks-scale-down-mode/ - <p>By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete <em>or</em> deallocate nodes.</p> -<p>Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. However, you will still need to pay for any storage that the node is using. Having persistent storage also means that any container images that were cached on the node will still be there when the node starts back up. This can be a major performance benefit if you are using Windows containers because the images for these containers are typically very large.</p> -<p>Scale down mode can be configured in several ways. Here, we will look at configuring it via the Azure CLI and Terraform.</p> -<p>Azure CLI:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>az aks nodepool update --scale-down-mode Deallocate --name nplinux01 --cluster-name myAKSCluster --resource-group myResourceGroup -</span></span></code></pre></div><p>Terraform:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-hcl" data-lang="hcl"><span style="display:flex;"><span><span style="color:#66d9ef">resource</span> <span style="color:#e6db74">&#34;azurerm_kubernetes_cluster_node_pool&#34; &#34;nodepool&#34;</span> { -</span></span><span style="display:flex;"><span> name <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;nplinux01&#34;</span> -</span></span><span style="display:flex;"><span> kubernetes_cluster_id <span style="color:#f92672">=</span> <span style="color:#66d9ef">azurerm_kubernetes_cluster</span>.<span style="color:#66d9ef">example</span>.<span style="color:#66d9ef">id</span> -</span></span><span style="display:flex;"><span> vm_size <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Standard_DS2_v2&#34;</span> -</span></span><span style="display:flex;"><span> node_count <span style="color:#f92672">=</span> <span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span> scale_down_mode <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Deallocate&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> tags <span style="color:#f92672">=</span> { -</span></span><span style="display:flex;"><span> Environment <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;lab&#34;</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><em>At the time of this writing, Terraform does not support configuring scale-down mode for the default AKS node pool.</em> -<em>Node pools using ephemeral disks do not support &lsquo;deallocate&rsquo; mode</em></p> - - - + http://localhost:1313/posts/2022-07-19-aks-scale-down-mode/ + By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete or deallocate nodes. Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. + Scheduled Kubernetes Worker Node Maintenance with Kured - https://rnemeth90.github.io/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ + http://localhost:1313/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ Fri, 15 Jul 2022 18:18:50 +0000 - - https://rnemeth90.github.io/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ - <p>If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this?</p> -<p>Weaveworks created a great tool for simplifying these steps: Kured (the <em><strong>Ku</strong>bernetes <strong>Re</strong>boot <strong>D</strong>aemon</em>). Let’s start by deploying Kured to our cluster.</p> -<p>Kured can be deployed in one of several ways. In this article, we’ll focus on deploying it via Helm. This is the simplest and quickest way to get it running in our cluster.</p> -<p>Follow these steps to install the Helm chart:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># 1) Add the Kured Helm repository</span> -</span></span><span style="display:flex;"><span>helm repo add kured https://weaveworks.github.io/kured -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 2) Update your local Helm chart repository cache</span> -</span></span><span style="display:flex;"><span>helm repo update -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 3) Create a dedicated namespace where you would like to deploy kured</span> -</span></span><span style="display:flex;"><span>kubectl create namespace kured -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 4) Install kured in that namespace with Helm 3 (only on Linux nodes)</span> -</span></span><span style="display:flex;"><span>helm install kured kured/kured --namespace kured --set nodeSelector.<span style="color:#e6db74">&#34;kubernetes\.io/os&#34;</span><span style="color:#f92672">=</span>linux -</span></span></code></pre></div><p>If all went well with the command above, that’s it, you’re done! Have a nice day! 🙂</p> -<p>If you want to test Kured, login to one of your Linux nodes, and install some patches with your package manager of choice (any patch that requires a reboot, typically patches that modify kernel headers). Then, check for a file named ‘reboot-required’ in /var/run:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>ls -lisa /var/run/reboot-required -</span></span></code></pre></div><p>If you installed patches, and this file does not exist, none of your patches require a reboot. We can still fake the system into thinking a reboot is required by manually creating the ‘reboot-required’ file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo touch /var/run/reboot-required -</span></span></code></pre></div><p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-1.png" alt=""></p> -<p>Then, we’ll use Kubetail to tail the logs of all our Kured pods:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubetail -label kured --namespace kured -</span></span></code></pre></div><p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-1024x749.png" alt=""></p> -<p>By default, Kured checks for the existence of the sentinel file every 60 minutes. However, this behavior can be changed. See the github repo for more info:</p> -<p><img src="https://github.com/weaveworks/kured#reboot-sentinel-file--period" alt="weaveworks/kured: Kubernetes Reboot Daemon"></p> -<p>Scheduling on the node should be disabled if you are within the Kured schedule</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-2.png" alt=""></p> -<p>Now that the node is cordoned off, running pods on the node are drained, and the node is rebooted.</p> -<p>That’s it for this article. Have a great day!</p> - - - + http://localhost:1313/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ + If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this? Weaveworks created a great tool for simplifying these steps: Kured (the Kubernetes Reboot Daemon). + Running Docker in WSL v1 - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ Sun, 26 Jun 2022 15:00:28 +0000 - - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ - <p>I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate.</p> -<p>Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. I receive this nice message:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ docker -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>The command <span style="color:#e6db74">&#39;docker&#39;</span> could not be found in this WSL <span style="color:#ae81ff">1</span> distro. -</span></span><span style="display:flex;"><span>We recommend to convert this distro to WSL <span style="color:#ae81ff">2</span> and activate -</span></span><span style="display:flex;"><span>the WSL integration in Docker Desktop settings. -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>See https://docs.docker.com/docker-for-windows/wsl/ <span style="color:#66d9ef">for</span> details. -</span></span></code></pre></div><p>So I’m in somewhat of a catch-22 here…</p> -<p>To work around this problem until a proper solution is found, I was able to get Docker working with WSL v1.</p> -<p>If you happen to be having a similar issue (and it seems like quite a few people are, considering the number of Github posts I found), just follow these steps:</p> -<ul> -<li>Expose the Docker daemon in docker desktop settings:</li> -</ul> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/02/image-10-1024x585.png"></a></p> -<p>Install the stand-alone Docker client in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ tar zxvf docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ cd docker -</span></span></code></pre></div><p>Set the default Docker daemon in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>export DOCKER_HOST<span style="color:#f92672">=</span>tcp://localhost:2375 -</span></span></code></pre></div><p>Verify you can connect to Docker running on Windows from within WSL:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>./docker info -</span></span></code></pre></div><p>This is also beneficial in that you only have one Docker host to manage your containers, network, etc., rather than two.</p> - - - + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ + I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. + EF Core &#8211; Unable to create an object of type DbContext - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ Sun, 12 Jun 2022 13:58:52 +0000 - - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ - <p>This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it!</p> -<p>When running EF Core migrations in a solution, you may come across this error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-1-1024x142.png"></a></p> -<p>There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio.</p> -<p>To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-2.png"></a></p> -<p>If you are using clean architecture, or some other architecture that has your startup context and your dbContext in different projects, you will need to set your startup project to your runtime, and the ‘Default Project’ in the package manager console to the project containing your dbContext.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-3-1024x493.png"></a></p> - - - + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it! When running EF Core migrations in a solution, you may come across this error: There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio. To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’. + Remove Kubernetes Namespace Stuck in the Terminating State - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ Sat, 04 Jun 2022 18:29:41 +0000 - - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ - <p>In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state.</p> -<p>A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. One day, you decide you no longer want this blog, so you plan to delete it. Rather than tediously deleting all of the various entities associated with this blog, you can delete the namespace that contains these entities. This will essentially ‘cascade delete’ the resources within the namespace as well.</p> -<p>After deleting the namespace for your blog, you notice that it still exists, but the state of it is ‘Terminating’, and it has been like this for a long time (hours or maybe even days).</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/06/image.png"></a></p> -<p>Kubernetes will occassionally fail to delete third-party resources when deleting a namespace, causing the namespace to linger. This can happen if the third-party API managing the resource is not responding to requests. To verify if any of these resources still exist, use this command:</p> -<pre tabindex="0"><code>kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get --show-kind --show-all --ignore-not-found -n &lt;terminating-namespace&gt; -</code></pre><p>If you happen to see any resources in the output, you can try force deleting them and then try to delete the namespace again.</p> -<p>In my experience, the majority of the time you will not find any resources still hanging around. Rather, the namespace will be completely empty. What is going on here?</p> -<p>Let’s take a look at the namespace:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ae81ff">$ kubectl get namespace darn-c101 -o yaml</span> -</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Namespace</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">annotations</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">kubectl.kubernetes.io/last-applied-configuration</span>: <span style="color:#ae81ff">|</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">kubernetes.io/metadata.name</span>: <span style="color:#ae81ff">darn-c101</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">finalizers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">kubernetes</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">status</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">conditions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">lastTransitionTime</span>: <span style="color:#e6db74">&#34;2022-06-01T19:05:31Z&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">message: &#39;Some content in the namespace has finalizers remaining</span>: <span style="color:#ae81ff">darn-c101.geekyryan.io/finalizer in 1 resource instances&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">reason</span>: <span style="color:#ae81ff">SomeFinalizersRemain</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">status</span>: <span style="color:#e6db74">&#34;True&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">NamespaceFinalizersRemaining</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">phase</span>: <span style="color:#ae81ff">Terminating</span> -</span></span></code></pre></div><p>Notice the inclusion of the finalizers field in the above JSON. Some namespaces have a finalizer defined under spec.</p> -<p>A finalizer is a special metadata key that tells Kubernetes to wait until a specific condition is met before it fully deletes a resource. Much like a finalizer in the .NET framework (does Java have those too? 😀 )</p> -<p>So when you run a command like <code>kubectl delete namespace &lt;namespace&gt;</code>, Kubernetes checks for a finalizer in the <code>metadata.finalizers</code> field. If the resource defined in the finalizer cannot be deleted, then the namespace is not deleted either. This puts the namespace into a perpetual terminating state and is never actually deleted.</p> -<p>When an object has been terminating for an excessive time, check its finalizers by inspecting the <code>metadata.finalizers</code> field in its YAML.</p> -<p>So we now know what the problem is. How can we solve it? Well, it’s actually quite simple. If you are using bash, use this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> -</span></span><span style="display:flex;"><span>namespaces<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>kubectl get ns --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Terminating -o jsonpath<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;{range .items[*]}{.metadata.name}{&#34;\n&#34;}{end}&#39;</span><span style="color:#66d9ef">)</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -z <span style="color:#e6db74">&#34;</span>$namespaces<span style="color:#e6db74">&#34;</span><span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">&#34;No namespaces to delete.&#34;</span> -</span></span><span style="display:flex;"><span> exit -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> namespace in $namespaces -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">do</span> -</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">&#34;[Removing Namespace]: </span>$namespace<span style="color:#e6db74">&#34;</span> -</span></span><span style="display:flex;"><span> kubectl get namespace $namespace -o json | tr -d <span style="color:#e6db74">&#34;\n&#34;</span> | sed <span style="color:#e6db74">&#34;s/\&#34;finalizers\&#34;: \[[^]]\+\]/\&#34;finalizers\&#34;: []/&#34;</span> | kubectl replace --raw /api/v1/namespaces/$namespace/finalize -f - &gt; /dev/null 2&gt;&amp;<span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">done</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span> -</span></span></code></pre></div><p><a href="https://gist.github.com/rnemeth90/e83bb4c8808f0d28412cb40edb2487d3">Delete Terminating Kubernetes Namespaces with Bash (github.com)</a></p> -<p>It will search for any namespace that is stuck in the terminating state and forcefully remove it by removing the finalizers field and then using <code> kubectl replace</code> to commit the change back to the Kube API.</p> -<p>If you prefer Powershell, you can use this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$terminatingNamespaces = kubectl get ns --field-selector=status.phase==Terminating -o jsonpath=<span style="color:#e6db74">&#34;{range .items[*]}{.metadata.name}{&#39;\n&#39;}{end}&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($ns <span style="color:#66d9ef">in</span> $terminatingNamespaces) { -</span></span><span style="display:flex;"><span> Write-Verbose <span style="color:#e6db74">&#39;[FOUND]: Forcefully removing $ns&#39;</span> -</span></span><span style="display:flex;"><span> $jsonObj = kubectl get namespace $ns -o json | ConvertFrom-Json | foreach-object { $_.spec.finalizers = @(); $_ } | -</span></span><span style="display:flex;"><span> convertto-json | kubectl replace --raw /api/v1/namespaces/$namespace/finalize <span style="color:#f92672">-f</span> - -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><a href="https://gist.github.com/rnemeth90/19d7de622a5009c1cf908c5d4deb5358">Delete Terminating Kubernetes Namespaces with Powershell (github.com)</a></p> -<p>It does the same thing as the bash script, just in more of a Window-zy way.</p> -<p>It’s that simple. I hope this was helpful. If you have any questions, comments, or concerns, please feel free to reach out.</p> - - - + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state. A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. + Injecting multiple Kubernetes volumes to the same directory in a pod - https://rnemeth90.github.io/posts/2022-04-30-injecting-multiple-kubernetes-volumes-to-the-same-directory-in-a-pod/ + http://localhost:1313/posts/2022-04-30-injecting-multiple-kubernetes-volumes-to-the-same-directory-in-a-pod/ Sat, 30 Apr 2022 14:21:05 +0000 - - https://rnemeth90.github.io/posts/2022-04-30-injecting-multiple-kubernetes-volumes-to-the-same-directory-in-a-pod/ - <p>We can inject configuration into containers using Kubernetes config maps and secrets. These objects can be consumed by a pod as environment variables, command-line arguments, or as configuration files mounted in a volume. For the subject of this article, we will focus on mounting multiple config maps/secrets into a single directory on a pod.</p> -<p>Mounting a configmap or secret in a Volume is relatively straightforward (for anyone familiar with Kubernetes primitives). Take for example the following deployment definition:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ConfigMap</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">application.properties</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> greeting=Hello -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> name=World</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>--- -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Secret</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-credentials</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">credentials.properties</span>: <span style="color:#ae81ff">&lt;base64 goes here&gt;</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">type</span>: <span style="color:#ae81ff">Opaque</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>--- -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Deployment</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">matchLabels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">template</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">busybox:latest</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">command</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">/bin/sh</span> -</span></span><span style="display:flex;"><span> - -<span style="color:#ae81ff">c</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">sleep 5000</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/config/application.properties</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readOnly</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-credentials-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/config/credentials.properties</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readOnly</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">configMap</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-credentials-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">secret</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">secretName</span>: <span style="color:#ae81ff">hello-world-credentials</span> -</span></span></code></pre></div><p>When this deployment is created, we see two directories are created in this pod (one for the configMap, and one for the secret). How can we mount these as two <em>files</em> in the ‘config’ directory, rather than two individual directories?</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/04/image.png"></a></p> -<p>The ~VolumeMounts~ directive within the container spec of the deployment has an optional (less-known) parameter named ‘subPath’. By using this parameter, we can mount a configMap and secret in the same directory within a pod.</p> -<p>Let’s focus on the following deployment spec:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ConfigMap</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">application.properties</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> greeting=Hello -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> name=World</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>--- -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Secret</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-credentials</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">credentials.properties</span>: <span style="color:#ae81ff">&lt;base64 goes here&gt;</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">type</span>: <span style="color:#ae81ff">Opaque</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>--- -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Deployment</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">matchLabels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">template</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">busybox:latest</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">command</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">/bin/sh</span> -</span></span><span style="display:flex;"><span> - -<span style="color:#ae81ff">c</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">sleep 5000</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/config/application.properties</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">subPath</span>: <span style="color:#ae81ff">application.properties</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readOnly</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-credentials-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/config/credentials.properties</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">subPath</span>: <span style="color:#ae81ff">credentials.properties</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readOnly</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">configMap</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-credentials-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">secret</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">secretName</span>: <span style="color:#ae81ff">hello-world-credentials</span> -</span></span></code></pre></div><p>Now, if we deploy this, we can see that we have two files in the ‘config’ directory of the pod, rather than a subdirectory for each config/secret:</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/04/image-1.png"></a></p> -<p>In this example, the key application.properties from the configuration map will be mounted to a file with the same name under /config/, and the secret value credentials.properties will be mounted to a second file under that directory. Both files will be read-only to the application.</p> - - - + http://localhost:1313/posts/2022-04-30-injecting-multiple-kubernetes-volumes-to-the-same-directory-in-a-pod/ + We can inject configuration into containers using Kubernetes config maps and secrets. These objects can be consumed by a pod as environment variables, command-line arguments, or as configuration files mounted in a volume. For the subject of this article, we will focus on mounting multiple config maps/secrets into a single directory on a pod. Mounting a configmap or secret in a Volume is relatively straightforward (for anyone familiar with Kubernetes primitives). + Kubernetes Storage Simplified - https://rnemeth90.github.io/posts/2022-03-01-kubernetes-storage-simplified/ + http://localhost:1313/posts/2022-03-01-kubernetes-storage-simplified/ Tue, 01 Mar 2022 08:37:58 +0000 - - https://rnemeth90.github.io/posts/2022-03-01-kubernetes-storage-simplified/ - <p>In this blog post, we will attempt to explain the current storage options that exist in Kubernetes. If you are new to Kubernetes, learning about its capabilities of managing the application state can be a daunting task.</p> -<p>Container images are built-in layers, with the runtime layer being writable. However, any files on this writable layer are only available for the container’s lifetime. We can mount a volume to a directory inside the container to have persistent data.</p> -<p>Kubernetes storage uses the concepts of volumes. Ephemeral volumes are called volumes and only last the lifetime of a pod, and “persistent volumes” are used for long-term storage. A typical use case for Ephemeral volumes is storing logs that are not sent to stdout.</p> -<p>Mounting a persistent volume inside a container allows you to persist the state of your application long after the container is terminated. Persistent volumes can also take advantage of the typical storage idiosyncrasies such as backup, compression, and encryption.</p> -<h2 id="persistent-volumes" >Persistent Volumes -<span> - <a href="#persistent-volumes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Kubernetes has several types of persistent volumes. At its core, a persistent volume is simply a directory mounted inside a pod. How that volume is created, the configuration options and the medium that backs it are all determined by the type of volume created.</p> -<p>There are several types of volumes available, too many to list here. You may commonly see some volume types: NFS, iSCSI, hostpath, and local. If your Kubernetes cluster exists in a cloud environment such as Azure or AWS, other volume types are available to you (azureDisk, azureFile, and awsElasticBlockStore, respectively). A complete list of types can be found here:</p> -<p><a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes">https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes</a></p> -<p>Creating a persistent volume is generally a simple task. The first step is determining the type of volume to create. In this post, we will cover creating a local volume. A local volume represents a disk, partition, or directory shared from a node. Local volumes are subject to the availability of the underlying node, meaning that if the node is offline, the volume is also offline and will not be accessible by any pod. Because of this, local volumes should not be used in production.</p> -<p>A persistent volume can only be created using a declarative approach. To create a persistent local volume, use the following YAML definition:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolume</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">example-pv</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">capacity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMode</span>: <span style="color:#ae81ff">Filesystem</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteOnce</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeReclaimPolicy</span>: <span style="color:#ae81ff">Delete</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">local-storage</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">local</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># the path to the volume or directory on the node</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/mnt/disks/ssd1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeAffinity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">required</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeSelectorTerms</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">matchExpressions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">key</span>: <span style="color:#ae81ff">kubernetes.io/hostname</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">operator</span>: <span style="color:#ae81ff">In</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">values</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># name of the node sharing the volume</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">node01</span> -</span></span></code></pre></div><p>When creating a persistent volume of this type, you must specify a node affinity. This ensures that the Kubernetes scheduler schedules any pods requesting access to this volume on the correct node. For example, any pod requesting access to the persistent volume named ‘example-PV will only be scheduled on the node ‘node01’.</p> -<p>Let’s dive into this persistent volume spec a bit more:</p> -<p>You can change the capacity of the persistent volume by updating:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">capacity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span></code></pre></div><p>The accessModes will be determined by the storage provider being used. There are generally 3 access modes available: ReadWriteOnce, ReadWriteMany, and ReadOnlyMany.</p> -<ul> -<li>ReadWriteOnce – The volume can be mounted as read-write by a single node</li> -<li>ReadWriteMany – The volume can be mounted as read-write by many nodes</li> -<li>ReadOnlyMany – The volume can be mounted as read-only by many nodes</li> -</ul> -<p>The “persistentVolumeReclaim” policy determines what happens to a persistent volume when it is no longer mounted by any pods (i.e., there are no claims to it, more on this later). There are three options available for the reclaim policy:</p> -<ul> -<li>Retain – The persistent volume is kept as-is. It must be manually removed when no longer needed.</li> -<li>Recycle – The persistent volume is scrubbed and can be re-used by other pods</li> -<li>Delete – The persistent volume is deleted.</li> -</ul> -<p>Currently, only NFS and hostPath volumes support recycling. Cloud storage providers (Azure, AWS, and GCE) support deletion.</p> -<p>The other aspects of this spec are unique to the volume being used. Since we are using a local volume here, we must specify the path to the directory or volume on the host and the host which is sharing the directory or volume:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span> <span style="color:#f92672">local</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># the path to the volume or directory on the node</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/mnt/disks/ssd1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeAffinity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">required</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeSelectorTerms</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">matchExpressions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">key</span>: <span style="color:#ae81ff">kubernetes.io/hostname</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">operator</span>: <span style="color:#ae81ff">In</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">values</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># name of the node sharing the volume</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">node01</span> -</span></span></code></pre></div><h2 id="ephemeral-volumes" >Ephemeral Volumes -<span> - <a href="#ephemeral-volumes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Note: The Kubernetes documentation recognizes configMaps and Secrets as ephemeral volumes. However, in this article, we will only discuss ephemeral volumes used for data storage (emptyDir volumes).</p> -<p>Ephemeral volumes are defined within the context of a pod. This means that you cannot create an ephemeral volume on its own. Instead, define the ephemeral volume in the pod or a deployment spec.</p> -<p>Ephemeral volumes are useful in a few scenarios:</p> -<ol> -<li>You want to share data between multiple containers in a pod</li> -<li>You want to cache temporary information such as log files</li> -<li>You need scratch space to store data before it is processed by another container or pod</li> -</ol> -<p>If one of the containers in the pod happens to restart, data on the ephemeral volume will still exist; as long as one of the containers is mounting, it stays online. In other words, if a pod mounting the ephemeral volume is removed from a node, data on the ephemeral volume is lost. However, if a pod crashes, the data on the volume remains intact.</p> -<p>As stated previously, creating an ephemeral volume is done as part of the pod or deployment template:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/cache</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">emptyDir</span>: {} -</span></span></code></pre></div><p>If the template, you add a volume of type ’emptyDir’ in the ‘volumes’ spec and name it. You can mount this volume in any container in the pod. The volume does not have to be mounted to the same directory in each container.</p> -<h2 id="persistent-volume-claims" >Persistent Volume Claims -<span> - <a href="#persistent-volume-claims"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>A persistentVolumeClaim (often referred to as a ‘PVC’) is used by a pod to create a ‘claim’ on storage. Using a PVC, a pod can mount multiple persistent volumes simultaneously to any directory in the pod.</p> -<p>PersistentVolumeClaim’s are a Kubernetes primitive that can be deployed from a manifest:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fast-storage-pvc</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMode</span>: <span style="color:#ae81ff">Filesystem</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">8Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">fast</span> -</span></span></code></pre></div><p>Most of the options in the manifest above seem pretty obvious. The volumeMode specifies whether to consume the persistent volume as a FileSystem or block device. The resources section helps specify the amount of storage you require (8Gi in this example). We will cover the storageClassName in the next section. Finally, the accessModes are identical to those described above in the Persistent Volumes section.</p> -<p>Pods access a volume by using the persistentVolumeClaim as volume. Claims must exist in the same namespace as the pod using the claim. The controller finds the claim in the pods’ namespace and uses it to find a persistent volume capable of backing the claim. The volume is then mounted on the host and attached to the pod.</p> -<p>To create a pod that utilizes a PVC, use the following yaml definition:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/mnt/share</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span></code></pre></div><h2 id="storage-classes" >Storage Classes -<span> - <a href="#storage-classes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>In this article, we will only be referencing Kubernetes storage classes with respect to dynamic provisioners. If you would like to learn more, please reference the Kubernetes docs:</p> -<p><a href="https://bit.ly/3ruJD2A">https://bit.ly/3ruJD2A</a></p> -<p>Storage Classes have many uses. Kubernetes is unopinionated about what a storage class represents. They can be used to represent different characteristics of storage (performance, compression method, file system modes, etc.). Storage Classes can also be used to provision persistent volumes dynamically, which will be the focus of this article.</p> -<p>Storage classes are often packaged with CSI drivers. Each StorageClass contains the fields “provisioner”, “parameters”, and “reclaimPolicy”. The provisioner field is used to determine what CSI driver is used for provisioning volumes.</p> -<p>This is an example of the storage class packaged with the AzureFiles CSI driver:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">StorageClass</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">storage.k8s.io/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azurefileshare</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">provisioner</span>: <span style="color:#ae81ff">file.csi.azure.com</span> <span style="color:#75715e"># replace with &#34;kubernetes.io/azure-file&#34; if aks version is less than 1.21</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">mountOptions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">dir_mode=0777</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">file_mode=0777</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">uid=0</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">gid=0</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">mfsymlinks</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">cache=strict</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">actimeo=30</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">parameters</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">skuName</span>: <span style="color:#ae81ff">Standard_LRS</span> -</span></span></code></pre></div><p>You can see in the above manifest that the provisioner is set to ‘file.csi.azure.com.’ When a pod uses a PVC in its manifest that references this storage class, the provisioner will dynamically manage the underlying storage.</p> -<p>The name of the storageClass is referenced in the persistentVolumeClaim:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">8Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">azurefileshare</span> -</span></span></code></pre></div><p>You could then reference this PVC in a pod:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/mnt/share</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span></code></pre></div><p>That concludes this article. I know that is a lot of information! As always, if you have any questions or comments, please reach out.</p> - - - + http://localhost:1313/posts/2022-03-01-kubernetes-storage-simplified/ + In this blog post, we will attempt to explain the current storage options that exist in Kubernetes. If you are new to Kubernetes, learning about its capabilities of managing the application state can be a daunting task. Container images are built-in layers, with the runtime layer being writable. However, any files on this writable layer are only available for the container’s lifetime. We can mount a volume to a directory inside the container to have persistent data. + Accessing Secrets Securely in Azure DevOps Pipelines - https://rnemeth90.github.io/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ + http://localhost:1313/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ Sat, 19 Feb 2022 16:02:50 +0000 - - https://rnemeth90.github.io/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ - <p>This post will cover a secure method for accessing secrets in Azure DevOps pipelines.</p> -<h2 id="why-azure-key-vault" >Why Azure Key Vault? -<span> - <a href="#why-azure-key-vault"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Azure Key Vault is an Azure cloud service used to securely store secrets, keys, and certificates. A secret can be any string of characters, such as API keys, passwords, URLs, etc. Azure Key Vault encrypts data at rest and in transit using HTTPS. Depending on the type of Key Vault you are using, data at rest is encrypted using software encryption (AES 256) or HSM-backed keys.</p> -<p>Azure Key Vault also gives us the ability to control access to secrets, keys, and certificates using native Key Vault access policies or the newer option of Azure IAM (RBAC) integration.</p> -<h2 id="what-are-variable-groups" >What are Variable Groups? -<span> - <a href="#what-are-variable-groups"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>It’s all in the name. Variable groups are simply a method of grouping Azure DevOps pipeline variables. If you created a release for an application named MyAwesomeApp, you could create a variable group named myawesomeapp-var-group that could then store all of the variables you reference in the release. It’s simply a method of organizing variables.</p> -<p>You apply permissions to variable groups so that only certain people and pipelines/releases are able to use them.</p> -<p>You can read more here about variable groups and their usage:</p> -<p><a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/library/variable-groups?view=azure-devops&amp;tabs=yaml#use-a-variable-group">https://docs.microsoft.com/en-us/azure/devops/pipelines/library/variable-groups?view=azure-devops&amp;tabs=yaml#use-a-variable-group</a></p> -<h2 id="creating-a-key-vault-and-adding-secrets" >Creating a Key Vault and Adding Secrets -<span> - <a href="#creating-a-key-vault-and-adding-secrets"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p><strong>If you already have a Key Vault, skip this section.</strong></p> -<p>In this post, we will create a Key Vault using the AzureCLI. To create the Vault and a secret, run these commands:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># Create a resource group</span> -</span></span><span style="display:flex;"><span>az group create --location &lt;location&gt; --name &lt;resource-group-name&gt; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Create a KeyVault</span> -</span></span><span style="display:flex;"><span>az keyvault create --name &lt;keyvault-name&gt; --resource-group &lt;resource-group-name&gt; --enable-soft-delete -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Create some secrets in the Key Vault</span> -</span></span><span style="display:flex;"><span>az keyvault secret set --name username --vault-name &lt;keyvault-name&gt; --value &lt;username&gt; -</span></span><span style="display:flex;"><span>az keyvault secret set --name password --vault-name &lt;keyvault-name&gt; --value &lt;password&gt; -</span></span><span style="display:flex;"><span>az keyvault secret set --name tenantId--vault-name &lt;keyvault-name&gt; --value &lt;tenant id&gt; -</span></span></code></pre></div><p>You will need to update the location and resource group name with whatever values you want. You will also need to update the username, password, and your Azure AD tenant ID. The username you choose will need read access to your subscription.</p> -<h2 id="creating-a-variable-group" >Creating a Variable Group -<span> - <a href="#creating-a-variable-group"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Now we’ll create the variable group in Azure DevOps.</p> -<p>Go to your Azure DevOps project &gt; Pipelines &gt; Library and click “+ Variable Group”:</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image.png"></a></p> -<p>Give your variable group a name. Then toggle the switch “Link secrets from an Azure key vault as variables”. Select your Azure Subscription (you may need to authorize DevOps access to the subscription, and then select the Key Vault.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-1.png"></a></p> -<p>Now we can add the secrets from the Key Vault to the variable group. Under “Variables”, click the “+ Add” button. Select the checkbox next to any secrets you want to add to the variable group, and then click “Ok”.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-7.png"></a></p> -<p>Finally, click the “Save” button. You now have a variable group with secrets linked to a Key Vault. Notice the name of the secret is the only thing visible from the variable group. If you were to update the secret value in the Key Vault, Azure DevOps would automatically pick up the new value.</p> -<h2 id="use-the-variable-group-in-a-pipeline" >Use the Variable Group in a Pipeline -<span> - <a href="#use-the-variable-group-in-a-pipeline"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Now that we have our variable group in place, let’s use it in a pipeline. In Azure DevOps, go to Pipelines and click “New pipeline”.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-8-1024x596.png"></a></p> -<p>Choose “Azure Repos Git” &gt; “&lt; your git repo&gt; “, “Starter Pipeline”, and then paste in the following code (You will need to update the ‘azureSubscription’ field with your SPN):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">variables</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">group</span>: <span style="color:#ae81ff">kv-secrets</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pr</span>: <span style="color:#ae81ff">none</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">stages</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">stage</span>: <span style="color:#ae81ff">print_resource_groups</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">jobs</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">job</span>: <span style="color:#ae81ff">print_resource_groups</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">continueOnError</span>: <span style="color:#66d9ef">false</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">task</span>: <span style="color:#ae81ff">AzureCLI@2</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">inputs</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">azureSubscription</span>: <span style="color:#e6db74">&#39;&lt;Your SPN&gt;&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">scriptType</span>: <span style="color:#e6db74">&#39;bash&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">scriptLocation</span>: <span style="color:#e6db74">&#39;inlineScript&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">inlineScript</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az login --service-principal --username $(username) --password $(password) --tenant $(tenantId) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az group list</span> -</span></span></code></pre></div><p>Now click “Save and Run”, and then “Save and Run” again.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-9-1024x596.png"></a></p> -<p>Once the pipeline finishes running, you can see that it was able to read the subscription and create a list of all resource groups found.</p> -<p>This is a simple example of using Key Vault credentials in a pipeline. But you can imagine how useful this could be in more complex scenarios.</p> -<p>That’s all for now. If you have any questions, feel free to reach out!</p> - - - + http://localhost:1313/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ + This post will cover a secure method for accessing secrets in Azure DevOps pipelines. Why Azure Key Vault? Link to heading Azure Key Vault is an Azure cloud service used to securely store secrets, keys, and certificates. A secret can be any string of characters, such as API keys, passwords, URLs, etc. Azure Key Vault encrypts data at rest and in transit using HTTPS. Depending on the type of Key Vault you are using, data at rest is encrypted using software encryption (AES 256) or HSM-backed keys. + Kubernetes Pod Eviction - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ Sat, 05 Feb 2022 23:49:16 +0000 - - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ - <p>In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation.</p> -<h2 id="what-is-pod-eviction" >What is Pod Eviction? -<span> - <a href="#what-is-pod-eviction"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. The most common of which is resource starvation on a node. This is referred to as “node-pressure eviction.”</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>NAME READY STATUS RESTARTS AGE -</span></span><span style="display:flex;"><span>nginx 0/1 Evicted <span style="color:#ae81ff">0</span> 10s -</span></span></code></pre></div><h2 id="eviction-process" >Eviction Process -<span> - <a href="#eviction-process"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The kubelet process running on the node monitors resources such as CPU, memory, disk space, inodes, etc. When one of these resources reaches a certain consumption level, the kubelet will first attempt to clean up resources by deleting non-running pods and images (in the case of storage starvation). The kubelet will then fail one or more pods on the node to reclaim resources. The class of the pod determines the order in which it does this.</p> -<p><strong>Pod Classes</strong></p> -<ul> -<li>Guaranteed: Pods that have requests and limits configured for both CPU and memory</li> -<li>Burstable: Pods with a resource request configured for memory or CPU</li> -<li>Best Effort: Pods without any requests or limits</li> -</ul> -<p>The kubelet will first evict any “best-effort” pods. If this is not enough, the kubelet will evict any “burstable” pods. Pods within the “guaranteed” class are theoretically safe from eviction.</p> -<p>During a node-pressure eviction, the kubelet sets the PodPhase for the selected pods to “Failed.” This causes the pods to terminate. If a daemonSet or replicaSet manages the pod, the Kubernetes controller-manager will create new pods on another node.</p> -<h2 id="recovery" >Recovery -<span> - <a href="#recovery"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Node-pressure eviction is almost always avoidable. We can prevent this type of issue by ensuring that we properly size our clusters and create resource limits for pods.</p> -<p><strong>Resource</strong> <strong>Requests and Limits:</strong></p> -<ul> -<li>Requests: The minimum amount of resources (CPU/memory) that a container needs to start.</li> -<li>Limits: The maximum amount of resources that a container is allowed to use.</li> -</ul> -<p>Pod resources and requests can be defined in a pod spec or deployment spec. Below is an example of a pod spec with resource requests and limits defined:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">frontend</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">nginx</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;64Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;250m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">limits</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;128Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;500m&#34;</span> -</span></span></code></pre></div><p>You will often need to clean up evicted pods manually. If you find that your cluster has a large amount of evicted pods, you can clean them up with the following kubectl commands:</p> -<p><strong>To see all failed pods in the cluster:</strong></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl get pod --all-namespaces --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Failed -</span></span></code></pre></div><p><strong>To remove all failed pods in the cluster:</strong></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl delete pod --all-namespaces --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Failed -</span></span></code></pre></div><p>I hope this article has been helpful. Please reach out if you have any questions or comments! Also, if you would like to learn more, take a look at the official Kubernetes docs:</p> -<p><a href="https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/">https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/</a></p> - - - + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ + In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation. What is Pod Eviction? Link to heading Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. + Azure Kubernetes sFTP Solution - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ + http://localhost:1313/posts/2022-01-16-azure-kubernetes-sftp-solution/ Sun, 16 Jan 2022 07:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ - <p>In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault.</p> -<p>Here is the link to my Github account where you can download the code mentioned in this article:</p> -<p><a href="https://github.com/rnemeth90/kubernetes-sftp">https://github.com/rnemeth90/kubernetes-sftp</a></p> -<p>We will work through the following steps in this article:</p> -<ol> -<li>Deploy the AzureFile CSI driver to the AKS cluster</li> -<li>Create a configMap that our initContainer will</li> -<li>Deploy a persistent volume claim that an Azure File share will back</li> -<li>Deploy a replicaSet consisting of our initContainer and application container</li> -<li>Deploy a service to serve traffic</li> -</ol> -<p>First, you will need to deploy the Azure Files CSI driver to your AKS cluster. AKS uses this daemon set to dynamically provision/destroy Azure NFSv4 File Shares. The Azure Files CSI driver creates a storage account in the node pool resource group, in which it will then provision the file share.</p> -<p>Deploying the Azure Files CSI driver is a simple task. You will need to run this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/install-driver.sh | bash -s master -- -</span></span></code></pre></div><p>You can use the following commands to verify that the daemon set has exists:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl -n kube-system get pod -o wide --watch -l app<span style="color:#f92672">=</span>csi-azurefile-controller -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>kubectl -n kube-system get pod -o wide --watch -l app<span style="color:#f92672">=</span>csi-azurefile-node -</span></span></code></pre></div><figure class="wp-block-coblocks-gallery-masonry masonry-grid has-border-radius-10 has-medium-gutter"><figure class="wp-block-image size-large masonry-brick">[![Image gallery image](https://rnemeth90.github.io/wp-content/uploads/2022/01/image-1-1024x434.png)](https://rnemeth90.github.io/wp-content/uploads/2022/01/image-1.png)</figure></figure>Next, you need to create a storage class by deploying this yaml file: -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl create -f https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/example/storageclass-azurefile-nfs.yaml -</span></span></code></pre></div><p>Read more about the AzureFiles CSI driver at the following Github link:</p> -<p><a href="https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/install-driver-on-aks.md">https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/install-driver-on-aks.md</a></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ConfigMap</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">creationTimestamp</span>: <span style="color:#66d9ef">null</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">testcm</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">init.sh</span>: |-<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> #!/bin/bash -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> CONF_FILE=&#34;/etc/sftp/users.conf&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> KEYVAULT=&#34;Insert name of Key Vault&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_ID=&#34;Insert service principal Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_PASSWORD=&#34;Insert service principal password&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_TENANT_ID=&#34;Insert Az AAD Tenant Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SUBSCRIPTION_ID=&#34;Insert Az Subscription Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az login --service-principal --username &#34;${AZ_SPN_ID}&#34; --password &#34;${AZ_SPN_PASSWORD}&#34; --tenant &#34;${AZ_SPN_TENANT_ID}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az account set --subscription &#34;${AZ_SUBSCRIPTION_ID}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETS+=($(az keyvault secret list --vault-name $KEYVAULT --query &#34;[].id&#34; -o tsv)) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> chmod 755 /home -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [[ -e $CONF_FILE ]]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> rm -rf &#34;${CONF_FILE}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> touch $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> else -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> touch $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> for SECRET in &#34;${SECRETS[@]}&#34;; do -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETNAME=$(basename $SECRET | tr -d &#39;\r&#39;) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETVALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $SECRETNAME --query &#39;value&#39; | tr -d &#39;&#34;&#39; | tr -d &#39;\r&#39;) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;$SECRETNAME:$SECRETVALUE:::upload&#34; &gt;&gt; $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> done -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [[ ! -s $CONF_FILE ]]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;** ERROR: user.conf is empty&#34; 1&gt;&amp;2 -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> exit 1 -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi</span> -</span></span></code></pre></div><p>The initContainer will use this configMap to read secrets from an Azure Key Vault and then write the secrets to the users.conf file. The users.conf file contains user account information. In the Key Vault, the secret name should be the username and the secret value should be the password. This Key Vault must exist and contain the secrets prior to deploying this solution.</p> -<p>When I deployed this solution in my environment, I used an Azure DevOps pipeline to create/manage the Key Vault with Terraform and then deploy the secrets using an inline Powershell script. However, this is beyond the scope of this article, and I will not be covering it here. You will also need to create a Service Principal in your AAD tenant and grant it access to the Key Vault. The Service Principal needs to have at least read access to the Key Vault.</p> -<p>Before deploying the configMap, you need to fill in values for these variables:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span> KEYVAULT<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert name of Key Vault&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert service principal Id&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_PASSWORD<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert service principal password&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_TENANT_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert Az AAD Tenant Id&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SUBSCRIPTION_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert Az Subscription Id&#34;</span> -</span></span></code></pre></div><p>These values pertain to the service principal with read access to the Key Vault. After filling out these variables, you can deploy the configMap using kubectl.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl create -f configmap.yaml -</span></span></code></pre></div><p>You can deploy the PVC using this yaml file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">azurefile-csi-nfs</span> -</span></span></code></pre></div><p>When creating the persistent volume claim for the deployment, you specify azurefile-csi-nfs as the StorageClass. This will create an NFSv4 share in a premium storage account. The reclaim policy of the storage class ensures that the file share is deleted when the associated Persistent Volume is deleted. Change the reclaim policy to “Retain” if you want the file shares to persist after deleting the PV. Furthermore, the storage class enables the file share to be expandable by modifying the storage request size on the PVC.</p> -<p>After deploying the PVC, you can verify its existence by running:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl get pvc -</span></span></code></pre></div><p>You should see output similar to the following (the manifest for the replicaSet is by far the most complicated of all the code referenced here):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Deployment</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">matchLabels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">strategy</span>: {} -</span></span><span style="display:flex;"><span> <span style="color:#f92672">template</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initContainer</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">chmodder</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">mcr.microsoft.com/azure-cli</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">command</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">/bin/sh</span> -</span></span><span style="display:flex;"><span> - -<span style="color:#ae81ff">c</span> -</span></span><span style="display:flex;"><span> - <span style="color:#e6db74">&#34;/scripts/init.sh&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/scripts</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">docker.io/atmoz/sftp:alpine</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">imagePullPolicy</span>: <span style="color:#ae81ff">IfNotPresent</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;64Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;250m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">limits</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;128Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;500m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">livenessProbe</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tcpSocket</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initialDelaySeconds</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">timeoutSeconds</span>: <span style="color:#ae81ff">5</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">periodSeconds</span>: <span style="color:#ae81ff">10</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">failureThreshold</span>: <span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readinessProbe</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tcpSocket</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initialDelaySeconds</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">timeoutSeconds</span>: <span style="color:#ae81ff">5</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">periodSeconds</span>: <span style="color:#ae81ff">10</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">failureThreshold</span>: <span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/home</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/etc/sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">dnsPolicy</span>: <span style="color:#ae81ff">ClusterFirst</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">restartPolicy</span>: <span style="color:#ae81ff">Never</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">configMap</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">emptyDir</span>: {} -</span></span></code></pre></div><p>You may need to change the CPU/memory requests and limits. These values worked for me, but your results may vary. You can also add/change the labels as you see fit.</p> -<p>This will handle routing traffic to our pods.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Service</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp-service</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">LoadBalancer</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">ports</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">protocol</span>: <span style="color:#ae81ff">TCP</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">targetPort</span>: <span style="color:#ae81ff">22</span> -</span></span></code></pre></div><p>Users will be connected in a round-robin fashion to the pods. This manifest will create a service of type LoadBalancer. Which will in turn create a new public Azure Load Balancer in the resource group that contains your Azure Kubernetes Service cluster if one does not already exist. If you already have a public load balancer, a new frontend IP address will be added.</p> -<p>That’s all for now. Please feel free to contact me if you have any questions.</p> - - - + http://localhost:1313/posts/2022-01-16-azure-kubernetes-sftp-solution/ + In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault. Here is the link to my Github account where you can download the code mentioned in this article: https://github.com/rnemeth90/kubernetes-sftp We will work through the following steps in this article: + WSUS: Update Files Not Downloading - https://rnemeth90.github.io/posts/2022-01-14-wsus-update-files-not-downloading/ + http://localhost:1313/posts/2022-01-14-wsus-update-files-not-downloading/ Fri, 14 Jan 2022 22:01:40 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-wsus-update-files-not-downloading/ - <p>This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-18_10h02_21.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-18_10h02_21.png" alt=""></a></p> -<p>You may also see this event (or similar) in the Event Log.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_32.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_32.png" alt=""></a></p> -<p>This problem is caused by not specifying a valid path when assigning the WSUS content drive when first installing the role. The first time you load the WSUS console after installing the role, you will be prompted to specify the path to store Windows Update files. WSUS does not like to have its content directory be the root of a partition. For example, if I were to specify “e:” as the path for the Windows Update content, the wizard would give you an error message stating that the path is not valid. However, it doesn’t prompt you to re-enter the path if you click close. The WSUS console opens immediately after and that invalid path is where WSUS will try to store your update files. This is and has been a known bug for a while and needs to be addressed by Microsoft. Evidence of the invalid path can be found in the registry under:</p> -<p>HKLM\Software\Microsoft\UpdateServices\Server\SetupContentDir</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_44.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_44.png" alt=""></a></p> -<p>If you come across this problem, you can change the ContentDir above to a valid path. Keep in mind that it cannot be the root of a partition. You need to specify a drive letter with a subfolder (eg: e:wsus).</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h54_54.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h54_54.png" alt=""></a></p> -<p>The other option is to reinstall the WSUS role. If you remove the role, the WID database is not removed, unless you remove that role as well (or manually delete the database). This means that when you reinstall the WSUS role, it will be able to use that same database and any clients that have contacted the WSUS server will immediately show up in the console. The same is true for update metadata. The new WSUS installation will still have the same approvals, denials, etc. as the old installation.</p> -<p>Regardless of what option you choose, I suggest rebooting the server after you make the changes.</p> - - - + http://localhost:1313/posts/2022-01-14-wsus-update-files-not-downloading/ + This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates: You may also see this event (or similar) in the Event Log. This problem is caused by not specifying a valid path when assigning the WSUS content drive when first installing the role. The first time you load the WSUS console after installing the role, you will be prompted to specify the path to store Windows Update files. + Active Directory Migration Toolkit The RPC Server is Unavailable - https://rnemeth90.github.io/posts/2022-01-14-active-directory-migration-toolkit-the-rpc-server-is-unavailable/ + http://localhost:1313/posts/2022-01-14-active-directory-migration-toolkit-the-rpc-server-is-unavailable/ Fri, 14 Jan 2022 21:55:56 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-active-directory-migration-toolkit-the-rpc-server-is-unavailable/ - <p>When migrating computer objects using the Active Directory Migration Tool, you may encounter the following error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_09.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_09.png" alt=""></a></p> -<p>In addition, the Migration Log may show the following error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_20.png" alt=""></a></p> -<p>This is typically caused by a host-side firewall. To resolve this, deploy a GPO to disable the Windows firewall prior to migrating the computer account. I like to create a special OU for computers (I typically name it “PreMigration”) that I will move computer objects to prior to migrating them. This OU will have two policies applied. One to disable the Windows Firewall and another to start the Remote Registry service. Both are required for the computer object to successfully migrate.</p> - + http://localhost:1313/posts/2022-01-14-active-directory-migration-toolkit-the-rpc-server-is-unavailable/ + When migrating computer objects using the Active Directory Migration Tool, you may encounter the following error: In addition, the Migration Log may show the following error: This is typically caused by a host-side firewall. To resolve this, deploy a GPO to disable the Windows firewall prior to migrating the computer account. I like to create a special OU for computers (I typically name it “PreMigration”) that I will move computer objects to prior to migrating them. - Continuous Deployment Models - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ + http://localhost:1313/posts/2022-01-14-continuous-deployment-models/ Fri, 14 Jan 2022 19:24:01 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ - <p>When deploying new software releases to servers or (insert -as-a-service&gt; here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments.</p> -<h2 id="bluegreen-deployments" >Blue/Green Deployments -<span> - <a href="#bluegreen-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. Instead, it gets deployed to another set of servers (blue) first. Since the blue servers are not currently serving any traffic for users, the deployment has no impact. However, once the deployment has been completed successfully and tested, users will be directed to the new deployment (blue). You can control all user traffic or a subset of user traffic if your load balancer supports it (referred to as ‘Progressive Exposure’).</p> -<p>The next release will then repeat the same process. Blue would be the current production environment, so you would first deploy to the green servers. This model requires two sets of identical hosts and a load balancer or reverse proxy in front of them. If there are any unexpected issues with the new release, it is straightforward to switch back to the previous release. The disadvantage to this type of model is that it requires having redundant environments (and potentially wasted resources). However, this is less of a concern if using container orchestration platforms such as Kubernetes.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/01/2022-01-19_07h57_58-1024x575.png" alt="Blue Green deployment model"></p> -<h2 id="immutable-servers" >Immutable Servers -<span> - <a href="#immutable-servers"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>There is an alternative method of blue/green deployments called “immutable servers”. This method is identical to blue/green deployments as described above. However, after switching user traffic over to the servers with the new release, the old servers are destroyed. They are not used again. This type of model becomes particularly efficient when using a pipeline that is capable of creating servers for you (i.e., Azure DevOps Pipelines)</p> -<h2 id="canary-deployments" >Canary Deployments -<span> - <a href="#canary-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>In a canary deployment, not all users are routed to the new release immediately. Only a limited percentage of users get access to the new release. These users are the canaries. They should be monitored closely, so it is important to be using Not all users are routed to the new release immediately in a canary deployment. Only a limited percentage of users get access to the latest release. These users are the canaries.</p> -<p>Organizations should monitor the canaries closely, so it is essential to be using monitoring software capable of looking at the statistics of a web application from the users’ perspective (for example, Application Insights). The number of canaries can increase until all traffic is directed to the new release over time. The most significant advantage of this method is limited exposure to issues. If a problem appears after the release is deployed, only a small subset of users will experience it. After you fix the issues and redeploy the release, it’s best to select a different group of users to be canaries.</p> -<h2 id="ring-based-deployments" >Ring Based Deployments -<span> - <a href="#ring-based-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>A ring-based deployment has multiple production environments. Each serves a limited number of users, similar to a canary deployment. However, you can have as many production environments as you want with a ring-based deployment. New releases are deployed to the rings one by one over time.</p> -<h2 id="feature-flag-deployments" >Feature Flag Deployments -<span> - <a href="#feature-flag-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Feature flags are used to expose new features to sets of users slowly. Unlike the other deployment models, they are not implemented in the infrastructure. Instead, they are typically implemented and enabled in code or database. An example would be a feature flag in a database that gives users access to a button on your web page. A developer could enable the flag for a set of users. These users would be able to see the button; other users would not. Feature flags can even toggle bug fixes or performance improvements.</p> -<p>I will cover implementing blue/green deployments in Azure using Azure DevOps and App Services in a future article.</p> - - - + http://localhost:1313/posts/2022-01-14-continuous-deployment-models/ + When deploying new software releases to servers or (insert -as-a-service&gt; here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments. Blue/Green Deployments Link to heading Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. + Deploy Azure VMs Using Azure Devops CI/CD Pipeline - https://rnemeth90.github.io/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ + http://localhost:1313/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ Fri, 14 Jan 2022 18:46:35 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ - <p>This article assumes that you have already created a pipeline in Azure Devops and have it linked to an Azure Devops repo. You will need to create a variable named $vmpassword and assign it the value stored in your key vault.</p> -<p>To create a release pipeline that will automatically create a VM (using the password stored in key vault for the local administrator account), do the following:</p> -<ol> -<li>Create a new release pipeline</li> -</ol> -<p><img src="https://www.rnemeth90.github.io/content/images/2021/01/image-13.png" alt=""></p> -<p>3. In the “select a template” box, choose “Empty Job”<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-14.png" alt=""></p> -<p>4. Select “Tasks” in the navigation bar, and then select the appropriate stage. For simplicities sake, we will be using 1 stage within this release.<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-15.png" alt=""></p> -<p>5. Click on the “+” in the Agent job bar, and then in the “Add tasks” section, type in “Key Vault”. Click “Azure Key Vault” and then click “Add”. <img src="https://www.rnemeth90.github.io/content/images/2021/01/image-16.png" alt=""></p> -<p>6. Click on the “Azure Key Vault:” task to configure it. Select your subscription, Key Vault, and the secrets filter. You can also create the $vmpassword variable as a variable within your devops project, rather than assigning it as a secret filter for the release. <img src="https://www.rnemeth90.github.io/content/images/2021/01/image-20.png" alt=""></p> -<p>7. In your Key Vault, you need to grant the devops account access to the Key Vault. To do this, go to your Key Vault and create a new access policy. This policy will be assigned to a service principal that is being used by your Azure Devops project. To find the ID of this service principal, go to your project settings, and under “Pipelines”, click on “Service Connections”. Then select the service connection that resembles your subscription. After doing this, click “Manage Service Principal”. In the service principal window, click “Manifest” and then find the “name” tag within the JSON.<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-19.png" alt=""></p> -<p>8. Now go back to your key vault, and assign an access policy for this service principal. Grant the principal read and list for secrets.</p> -<p>9. Add another agent job for the task (see step 6) and search for “azure cli”. Click on “Add” for Azure CLI. Configure the settings for this job as below:<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-18.png" alt=""></p> -<p>10. Save and run your pipeline. Give it some time to complete, and go take a look at your newly created VM. This is just a very simple example of creating a server as part of a CI/CD pipeline. You can then deploy your code to it, run some tests, destroy them VM, etc. Completely automated.<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-21.png" alt=""></p> - - - + http://localhost:1313/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ + This article assumes that you have already created a pipeline in Azure Devops and have it linked to an Azure Devops repo. You will need to create a variable named $vmpassword and assign it the value stored in your key vault. To create a release pipeline that will automatically create a VM (using the password stored in key vault for the local administrator account), do the following: Create a new release pipeline 3. + Azure Devops &#8211; Self Hosted Agent Service Won&#8217;t Start &#8211; Incorrect Function - https://rnemeth90.github.io/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ + http://localhost:1313/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ Fri, 14 Jan 2022 18:45:00 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ - <p>I setup a self hosted agent for Azure Devops this morning on Server 2012 R2 (legacy Visual Studio dependencies…) and found that I was unable to start the service. The error I received was “Error 1 Incorrect Function” when attempting to start the service in services.msc.</p> -<p>I was attempting to run the agent from within my user profile downloads folder. I originally was not aware the service would be running from this directory. I thought it would copy its binary files to program files directory or programdata, like 99% of all other apps. The service installs and attempts to run itself as the “network service” authority. This account does not have permission to a user profile folder by default, and the installation script is not able to grant it permission for some reason (I didn’t investigate this further). I removed the agent, moved the installation files to the root of c:, and then reinstalled. The agent service is now able to start successfully.</p> - + http://localhost:1313/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ + I setup a self hosted agent for Azure Devops this morning on Server 2012 R2 (legacy Visual Studio dependencies…) and found that I was unable to start the service. The error I received was “Error 1 Incorrect Function” when attempting to start the service in services.msc. I was attempting to run the agent from within my user profile downloads folder. I originally was not aware the service would be running from this directory. - Azure Tenant Maintenance &#8211; Purge Empty Resource Groups - https://rnemeth90.github.io/posts/2022-01-14-azure-tenant-maintenance-purge-empty-resource-groups/ + http://localhost:1313/posts/2022-01-14-azure-tenant-maintenance-purge-empty-resource-groups/ Fri, 14 Jan 2022 18:43:35 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-azure-tenant-maintenance-purge-empty-resource-groups/ - <p>This will be the first article in a series about maintaining Azure tenants and subscriptions.</p> -<p>If you currently, or have ever, worked in a large Azure environment, you know how easily resource creep can occur. Resource Groups, VM disks and network interfaces, network security groups, etc. can easily fall out of sight and be forgotten about. This isn’t a big concern for resources that are free of cost, like resource groups. However, if you delete several virtual machines, the disks that were attached to those virtual machines linger, and you continue to pay the cost of storing them.</p> -<p>In this blog post, we will review a script I created for removing empty resource groups. We will then add this script to an Azure Automation Account and link it to a schedule. We will assume you already have an Azure Automation Account in existence, and the Automation Account has a credential object named ‘AzureRunAsConnection’.</p> -<p>To get started, you can download the script here:</p> -<p><a href="https://github.com/rnemeth90/azure-automation/blob/master/clean-empty-resource-groups.ps1">https://github.com/rnemeth90/azure-automation/blob/master/clean-empty-resource-groups.ps1</a></p> -<p>This particular runbook will require that the “AZ.Resources” module be loaded in the Automation Account. To import this module, go to your automation account and then click on “Modules” under “Shared Resources”. Then, click on “Browse Gallery”.</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image.png"></a></p> -<p>In the search bar, type in “Az.resources”, then click on the module and click “Import”. If you see a message like this, you will need to add any modules that az.resources depends on before importing it.</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image-1.png"></a></p> -<p>You can go back and add those modules using the same process, and then attempt to import the “Az.resources” module again. Importing these modules may take several minutes. In my experience, it takes around 10-15 minutes.</p> -<p>Once these modules are imported you can import the PowerShell runbook you downloaded earlier from Github. To do that, browse to the Runbooks section of your Automation Account and then click “Import a Runbook”:</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image-2.png"></a></p> -<p>In the context menu that appears, browse to the runbook and upload it, choose “PowerShell” as the runbook type, and then click Create:</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image-3.png"></a></p> -<p>In the Editor Pane, click on “Test Pane”. This will bring you to the Test Pane for the runbook. This will allow you to test the runbook before running it in your environment. Click “Start” in the Test Pane. This particular runbook will output to screen any changes it will make, so you can see the results here.</p> -<p>As you can see here, the runbook did find some empty resource groups, but did not remove them:</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image-4.png"></a></p> -<p>This is because we have a variable in the runbook that controls whether or not any write/update actions will be taken on resources. Click the X in the upper right corner to go back to the editor, and change the value in the screenshot below from “0” to “1”.</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image-8.png"></a></p> -<p>If you’d like, you can test the runbook again, or you can click “Publish” to publish it to your Automation Account. Once it’s published, you can link it to a schedule so that it runs automatically.</p> -<p>Click “Publish”:</p> -<p>&lt;<a href="https://www.rnemeth90.github.io/content/images/2021/06/image-9.png"></a></p> -<p>Then, on the Runbook page, click “Schedules”, and then “Add a schedule”:</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image-10.png"></a></p> -<p>Fill out the wizard that pops up to create a schedule and link it to your workbook. This concludes this article.</p> -<p>In the next post, we will take a look at removing empty resource groups automatically. Stay tuned.</p> - - - + http://localhost:1313/posts/2022-01-14-azure-tenant-maintenance-purge-empty-resource-groups/ + This will be the first article in a series about maintaining Azure tenants and subscriptions. If you currently, or have ever, worked in a large Azure environment, you know how easily resource creep can occur. Resource Groups, VM disks and network interfaces, network security groups, etc. can easily fall out of sight and be forgotten about. This isn’t a big concern for resources that are free of cost, like resource groups. + Exam AZ-303: Microsoft Azure Architect Technologies Study Guide - https://rnemeth90.github.io/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ + http://localhost:1313/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ Wed, 16 Dec 2020 14:44:00 +0000 - - https://rnemeth90.github.io/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ - <p><span style="font-family: arial;">I recently passed the AZ-303 exam. Below are some of the resources I used to prepare for the exam. In addition to the links below, I also used Alan Rodrigues’ course on Udemy. </span></p> -<p><span style="font-family: arial;"><a href="https://www.udemy.com/course/az-102-azure-administrator-certification-transition/">https://www.udemy.com/course/az-102-azure-administrator-certification-transition/</a> -</span></p> -<p><span style="font-family: arial;">The Udemy course and Microsoft Docs are enough to pass the exam. The course has some good practice exams and labs that align well with what you’ll see on the real exam regarding difficulty. I was scoring in the high 90’s on the Udemy exams. On the real exam, my score was 923. So, I think, if you comprehend the material well, and get high scores on Udemy practice exams, you’ll do well on the real exam.</span></p> -<p><span style="font-family: arial;">Just wanted to share my experience, hopefully it helps.</span></p> -<p><strong><u><span style="font-size: large;">Implement and Monitor an Azure Infrastructure (50-55%)</span></u></strong></p> -<p><span style="font-size: medium;"><strong>Implement cloud infrastructure monitoring</strong></span></p> -<ul> -<li> -<p>monitor security</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/security-center/security-center-introduction">What is Azure Security Center?</a></p> -</li> -<li> -<p>monitor performance</p> -</li> -<li> -<p>configure diagnostic settings on resources</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/diagnostic-settings">Create diagnostic settings to send platform logs and metrics to different destinations</a></p> -</li> -<li> -<p>create a performance baseline for resources</p> -</li> -<li> -<p><a href="https://cloudacademy.com/course/analyzing-resource-utilization-azure/resource-baseline/">Analyzing Resource Utilization on Azure</a></p> -</li> -<li> -<p>monitor for unused resources</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cost-management-billing/costs/quick-acm-cost-analysis?tabs=azure-portal">Quickstart: Explore and analyze costs with cost analysis</a></p> -</li> -<li> -<p>monitor performance capacity</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/insights/vminsights-performance">How to chart performance with Azure Monitor for VMs</a></p> -</li> -<li> -<p>visualize diagnostics data using Azure Monitor</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/workbooks-overview">Azure Monitor Workbooks</a></p> -</li> -<li> -<p>monitor health and availability</p> -</li> -<li> -<p>monitor networking</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/insights/network-insights-overview">Azure Monitor for Networks</a></p> -</li> -<li> -<p>monitor service health</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/service-health/service-health-overview">Service Health overview</a></p> -</li> -<li> -<p>monitor cost</p> -</li> -<li> -<p>monitor spend</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cost-management-billing/costs/quick-acm-cost-analysis?tabs=azure-portal">Quickstart: Explore and analyze costs with cost analysis</a></p> -</li> -<li> -<p>report on spend</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cost-management-billing/understand/download-azure-invoice">View and download your Microsoft Azure invoice</a></p> -</li> -<li> -<p>configure advanced logging</p> -</li> -<li> -<p>implement and configure Azure Monitor insights, including App Insights, Networks, Containers</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/monitor-reference">What is monitored by Azure Monitor?</a></p> -</li> -<li> -<p>configure a Log Analytics workspace</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/learn/quick-create-workspace">Create a Log Analytics workspace in the Azure portal</a></p> -</li> -<li> -<p>configure logging for workloads</p> -</li> -<li> -<p>initiate automated responses by using Action Groups</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/action-groups">Create and manage action groups in the Azure portal</a></p> -</li> -<li> -<p>configure and manage advanced alerts</p> -</li> -<li> -<p>collect alerts and metrics across multiple subscriptions</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/alerts-metric">Create, view, and manage metric alerts using Azure Monitor</a></p> -</li> -<li> -<p>view Alerts in Azure Monitor logs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/alerts-activity-log">Create, view, and manage activity log alerts by using Azure Monitor</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement storage accounts</span></strong></p> -<ul> -<li> -<p>select storage account options based on a use case</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-account-create?tabs=azure-portal">Create a storage account</a></p> -</li> -<li> -<p>configure Azure Files and blob storage</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/files/storage-how-to-create-file-share?tabs=azure-portal">Create an Azure file share</a></p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-portal">Quickstart: Upload, download, and list blobs with the Azure portal</a></p> -</li> -<li> -<p>configure network access to the storage account</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-network-security">Configure Azure Storage firewalls and virtual networks</a></p> -</li> -<li> -<p>implement Shared Access Signatures and access policies</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-sas-overview">Grant limited access to Azure Storage resources using shared access signatures (SAS)</a></p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/rest/api/storageservices/define-stored-access-policy">Define a stored access policy</a></p> -</li> -<li> -<p>implement Azure AD authentication for storage</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-auth-aad">Authorize access to blobs and queues using Azure Active Directory</a></p> -</li> -<li> -<p>manage access keys</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-account-keys-manage?tabs=azure-portal">Manage storage account access keys</a></p> -</li> -<li> -<p>implement Azure storage replication</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/blobs/object-replication-configure?tabs=portal">Configure object replication for block blobs</a></p> -</li> -<li> -<p>implement Azure storage account failover</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-disaster-recovery-guidance">Disaster recovery and storage account failover</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement VMs for Windows and Linux</span></strong></p> -<ul> -<li> -<p>configure High Availability</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/manage-availability">Manage the availability of Linux virtual machines</a></p> -</li> -<li> -<p>configure storage for VMs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/managed-disks-overview">Introduction to Azure managed disks</a></p> -</li> -<li> -<p>select virtual machine size</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/sizes">Sizes for virtual machines in Azure</a></p> -</li> -<li> -<p>implement Azure Dedicated Hosts</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/dedicated-hosts-portal">Deploy VMs and scale sets to dedicated hosts using the portal</a></p> -</li> -<li> -<p>deploy and configure scale sets</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machine-scale-sets/quick-create-portal">Quickstart: Create a virtual machine scale set in the Azure portal</a></p> -</li> -<li> -<p>configure Azure Disk Encryption</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/windows/disk-encryption-overview">Azure Disk Encryption for Windows VMs</a></p> -</li> -</ul> -<p><span style="font-size: medium;"><strong>Automate deployment and configuration of resources</strong></span></p> -<ul> -<li> -<p>save a deployment as an Azure Resource Manager template</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/export-template-portal">Single and multi-resource export to a template in Azure portal</a></p> -</li> -<li> -<p>modify Azure Resource Manager template</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/overview">What are ARM templates?</a></p> -</li> -<li> -<p>evaluate location of new resources</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/view-activity-logs">View activity logs to monitor actions on resources</a></p> -</li> -<li> -<p>configure a virtual disk template</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/windows/capture-image-resource">Create a managed image of a generalized VM in Azure</a></p> -</li> -<li> -<p>deploy from a template</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/deploy-vms-from-vhd-templates/">Deploy Azure virtual machines from VHD templates</a></p> -</li> -<li> -<p>manage a template library</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/shared-image-galleries">Shared Image Galleries overview</a></p> -</li> -<li> -<p>create and execute an automation runbook</p> -</li> -<li> -<p><a href="https://azure.microsoft.com/en-us/blog/azure-automation-runbook-management/">Getting Started With Azure Automation – Runbook Management</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement virtual networking</span></strong></p> -<ul> -<li> -<p>implement VNet to VNet connections</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/vpn-gateway/vpn-gateway-howto-vnet-vnet-resource-manager-portal">Configure a VNet-to-VNet VPN gateway connection by using the Azure portal</a></p> -</li> -<li> -<p>implement VNet peering</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-peering-overview">Virtual network peering</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement Azure Active Directory</span></strong></p> -<ul> -<li> -<p>add custom domains</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/add-custom-domain">Add your custom domain name using the Azure Active Directory portal</a></p> -</li> -<li> -<p>configure Azure AD Identity Protection</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/identity-protection/overview-identity-protection">What is Identity Protection?</a></p> -</li> -<li> -<p>implement self-service password reset</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/tutorial-enable-sspr">Tutorial: Enable users to unlock their account or reset passwords using Azure Active Directory self-service password reset</a></p> -</li> -<li> -<p>implement Conditional Access including MFA</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/conditional-access/howto-conditional-access-policy-all-users-mfa">Conditional Access: Require MFA for all users</a></p> -</li> -<li> -<p>configure user accounts for MFA</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-userstates">Enable per-user Azure AD Multi-Factor Authentication to secure sign-in events</a></p> -</li> -<li> -<p>configure fraud alerts</p> -</li> -<li> -<p><a href="Enable%20per-user%20Azure%20AD%20Multi-Factor%20Authentication%20to%20secure%20sign-in%20events">Fraud alert</a></p> -</li> -<li> -<p>configure bypass options</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-server-settings#one-time-bypass">One-time bypass</a></p> -</li> -<li> -<p>configure Trusted IPs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-mfasettings#trusted-ips">Trusted IPs</a></p> -</li> -<li> -<p>configure verification methods</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/concept-sspr-howitworks#authentication-methods">Authentication methods</a></p> -</li> -<li> -<p>implement and manage guest accounts</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/external-identities/b2b-quickstart-add-guest-users-portal">Quickstart: Add guest users to your directory in the Azure portal</a></p> -</li> -<li> -<p>manage multiple directories</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/enterprise-users/licensing-directory-independence">Understand how multiple Azure Active Directory organizations interact</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement and manage hybrid identities</span></strong></p> -<ul> -<li> -<p>install and configure Azure AD Connect</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-install-express">Getting started with Azure AD Connect using express settings</a></p> -</li> -<li> -<p>identity synchronization options</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/plan-connect-user-signin">Azure AD Connect user sign-in options</a></p> -</li> -<li> -<p>configure and manage password sync and password writeback</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/tutorial-enable-sspr-writeback">Tutorial: Enable Azure Active Directory self-service password reset writeback to an on-premises environment</a></p> -</li> -<li> -<p>configure single sign-on</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-sso-quick-start">Azure Active Directory Seamless Single Sign-On: Quickstart</a></p> -</li> -<li> -<p>use Azure AD Connect Health</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/whatis-azure-ad-connect#what-is-azure-ad-connect-health">What is Azure AD Connect Health?</a></p> -</li> -</ul> -<p><strong><u><span style="font-size: large;">Implement Management and Security Solutions (25-30%)</span></u></strong></p> -<p><span style="font-size: medium;"><strong>Manage workloads in Azure</strong></span></p> -<ul> -<li> -<p>migrate workloads using Azure Migrate</p> -</li> -<li> -<p>assess infrastructure</p> -</li> -<li> -<p>select a migration method</p> -</li> -<li> -<p>prepare the on-premises for migration</p> -</li> -<li> -<p>recommend target infrastructure</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/migrate/tutorial-migrate-hyper-v">Migrate Hyper-V VMs to Azure</a></p> -</li> -<li> -<p>implement Azure Backup for VMs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/backup/backup-azure-vms-first-look-arm">Back up an Azure VM from the VM settings</a></p> -</li> -<li> -<p>implement disaster recovery</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/site-recovery/azure-to-azure-tutorial-enable-replication">Tutorial: Set up disaster recovery for Azure VMs</a></p> -</li> -<li> -<p>implement Azure Update Management</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/automation/update-management/enable-from-vm">Enable Update Management for an Azure VM</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement load balancing and network security</span></strong></p> -<ul> -<li> -<p>implement Azure Load Balancer</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/load-balancer/load-balancer-overview">What is Azure Load Balancer?</a></p> -</li> -<li> -<p>implement an application gateway</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/application-gateway/overview">What is Azure Application Gateway?</a></p> -</li> -<li> -<p>implement a Web Application Firewall</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/web-application-firewall/overview">What is Azure Web Application Firewall?</a></p> -</li> -<li> -<p>implement Azure Firewall</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/firewall/overview">What is Azure Firewall?</a></p> -</li> -<li> -<p>implement the Azure Front Door Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/frontdoor/quickstart-create-front-door">Quickstart: Create a Front Door for a highly available global web application</a></p> -</li> -<li> -<p>implement Azure Traffic Manager</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/traffic-manager/traffic-manager-overview">What is Traffic Manager?</a></p> -</li> -<li> -<p>implement Network Security Groups and Application Security Groups</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-network/network-security-groups-overview">Network security groups</a></p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-network/application-security-groups">Application security groups</a></p> -</li> -<li> -<p>implement Bastion</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/bastion/">Azure Bastion documentation</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement and manage Azure governance solutions</span></strong></p> -<ul> -<li> -<p>create and manage hierarchical structure that contains management groups</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/governance/management-groups/overview">What are Azure management groups?</a></p> -</li> -<li> -<p>subscriptions and resource groups</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-setup-guide/organize-resources?tabs=AzureManagementGroupsAndHierarchy">Organize your Azure resources effectively</a></p> -</li> -<li> -<p>assign RBAC roles</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal">Add or remove Azure role assignments using the Azure portal</a></p> -</li> -<li> -<p>create a custom RBAC role</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/custom-roles">Azure custom roles</a></p> -</li> -<li> -<p>configure access to Azure resources by assigning roles</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal">Add or remove Azure role assignments using the Azure portal</a></p> -</li> -<li> -<p>configure management access to Azure</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/manage-subscription-access-azure-rbac/">Manage access to an Azure subscription by using Azure role-based access control (RBAC)</a></p> -</li> -<li> -<p>interpret effective permissions</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/check-access">Quickstart: Check access for a user to Azure resources</a></p> -</li> -<li> -<p>set up and perform an access review</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/governance/access-reviews-overview">What are Azure AD access reviews?</a></p> -</li> -<li> -<p>implement and configure an Azure Policy</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/governance/policy/assign-policy-portal">Quickstart: Create a policy assignment to identify non-compliant resources</a></p> -</li> -<li> -<p>implement and configure an Azure Blueprint</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/governance/blueprints/overview">What is Azure Blueprints?</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Manage security for applications</span></strong></p> -<ul> -<li> -<p>implement and configure KeyVault</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/configure-and-manage-azure-key-vault/">Configure and manage secrets in Azure Key Vault</a></p> -</li> -<li> -<p>implement and configure Managed Identities</p> -</li> -<li> -<p><a href="https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=18fbca16-2224-45f6-85b0-f7bf2b39b3f3&amp;nonce=ef221978-b465-49a1-9226-e8a0e4d25480&amp;prompt=none&amp;redirect_uri=https%3A%2F%2Fdocs.microsoft.com%2F_themes%2Fdocs.theme%2Fmaster%2Fen-us%2F_themes%2Fglobal%2Fsign-in.html&amp;response_mode=fragment&amp;response_type=id_token&amp;scope=openid%20profile&amp;sso_reload=true&amp;state=silent%3A%2F%2Fhttps%3A%2F%2Fdocs.microsoft.com&amp;fromOrigin=https%3A%2F%2Fdocs.microsoft.com&amp;iframe-request-id=685d3411-99a9-4f94-81e4-d9b8af575600">What are managed identities for Azure resources?</a></p> -</li> -<li> -<p>register and manage applications in Azure AD</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app">Quickstart: Register an application with the Microsoft identity platform</a></p> -</li> -</ul> -<p><strong><u><span style="font-size: large;">Implement Solutions for Apps (10-15%)</span></u></strong></p> -<p><strong><span style="font-size: medium;">Implement an application infrastructure</span></strong></p> -<ul> -<li> -<p>create and configure Azure App Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/quickstart-dotnetcore?tabs=netcore31&amp;pivots=platform-linux">Quickstart: Create an ASP.NET Core web app in Azure</a></p> -</li> -<li> -<p>create an App Service Web App for Containers</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/deploy-run-container-app-service/">Deploy and run a containerized web app with Azure App Service</a></p> -</li> -<li> -<p>create and configure an App Service plan</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/app-service-plan-manage">Manage an App Service plan in Azure</a></p> -</li> -<li> -<p>configure an App Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/configure-common">Configure an App Service app in the Azure portal</a></p> -</li> -<li> -<p>configure networking for an App Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/web-sites-integrate-with-vnet">Integrate your app with an Azure virtual network</a></p> -</li> -<li> -<p>create and manage deployment slots</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/deploy-staging-slots">Set up staging environments in Azure App Service</a></p> -</li> -<li> -<p>implement Logic Apps</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/logic-apps/quickstart-create-first-logic-app-workflow">Quickstart: Create your first Logic Apps workflow – Azure portal</a></p> -</li> -<li> -<p>implement Azure Functions</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-azure-function">Create your first function in the Azure portal</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement container-based applications </span></strong></p> -<ul> -<li> -<p>create a container image</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/container-registry/container-registry-quickstart-task-cli">Quickstart: Build and run a container image using Azure Container Registry Tasks</a></p> -</li> -<li> -<p>configure Azure Kubernetes Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/aks/kubernetes-walkthrough-portal">Quickstart: Deploy an Azure Kubernetes Service (AKS) cluster using the Azure portal</a></p> -</li> -<li> -<p>publish and automate image deployment to the Azure Container Registry</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/container-instances/container-instances-using-azure-container-registry">Deploy to Azure Container Instances from Azure Container Registry</a></p> -</li> -<li> -<p>publish a solution on an Azure Container Instance</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/container-instances/container-instances-quickstart-portal">Quickstart: Deploy a container instance in Azure using the Azure portal</a></p> -</li> -</ul> -<p><strong><u>Implement and Manage Data Platforms (10-15%)</u></strong></p> -<p><strong><span style="font-size: medium;">Implement NoSQL databases</span></strong></p> -<ul> -<li> -<p>configure storage account tables</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/tables/table-storage-quickstart-portal">Quickstart: Create an Azure Storage table in the Azure portal</a></p> -</li> -<li> -<p>select appropriate CosmosDB APIs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/choose-api-for-cosmos-db/">Choose the appropriate API for Azure Cosmos DB</a></p> -</li> -<li> -<p>set up replicas in CosmosDB</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cosmos-db/distribute-data-globally">Distribute your data globally with Azure Cosmos DB</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement Azure SQL databases</span></strong></p> -<ul> -<li> -<p>configure Azure SQL database settings</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-sql/database/single-database-create-quickstart?tabs=azure-portal">Quickstart: Create an Azure SQL Database single database</a></p> -</li> -<li> -<p>implement Azure SQL Database managed instances</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-sql/managed-instance/sql-managed-instance-paas-overview">What is Azure SQL Managed Instance?</a></p> -</li> -<li> -<p>configure HA for an Azure SQL database</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-sql/database/high-availability-sla">High availability for Azure SQL Database and SQL Managed Instance</a></p> -</li> -<li> -<p>publish an Azure SQL database</p> -</li> -</ul> - - - + http://localhost:1313/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ + I recently passed the AZ-303 exam. Below are some of the resources I used to prepare for the exam. In addition to the links below, I also used Alan Rodrigues’ course on Udemy. https://www.udemy.com/course/az-102-azure-administrator-certification-transition/ The Udemy course and Microsoft Docs are enough to pass the exam. The course has some good practice exams and labs that align well with what you’ll see on the real exam regarding difficulty. I was scoring in the high 90’s on the Udemy exams. + Azure AD Sync &#8211; Set-MsolDirSyncEnabled : You cannot turn off Active Directory synchronization. - https://rnemeth90.github.io/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ + http://localhost:1313/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ Thu, 26 Nov 2020 16:31:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ - <p>I recently ran into a situation in my lab environment that required I resync all (2000+) user accounts to Azure AD. Though this sounds complex and daunting, its actually quite simple. T</p> -<p>The basic steps involve disabling sync, and then removing the user objects. This can all be done with two PowerShell commands:</p> -<p>1) Set-MsolDirSyncEnabled -EnableDirSync $false</p> -<p><a href="https://lh3.googleusercontent.com/-rGK18FXw7ns/X7_WthQR0CI/AAAAAAAAyCM/gg7MsY2fcVIcWMMbvxYzPpbpPyKwgHP8ACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image.png" alt=""></a></p> -<p>2) Get-MsolUser -All | Remove-MsolUser -force</p> -<p><a href="https://lh3.googleusercontent.com/-miyfN7OISGo/X7_WzDCc6iI/AAAAAAAAyCQ/PtHURTTVMQ4uypzO7L1UaLfyEs0fpYGdACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-1.png" alt=""></a></p> -<p>The account that you are currently running the commands as will not be removed.</p> -<p>To enable Azure AD Sync, you simply reverse the boolean operation on the Set-MsolDirSyncEnabled cmdlet above. However, I ran into an issue when trying to enable Azure AD Sync.</p> -<p><a href="https://lh3.googleusercontent.com/-R1TPVgYaEBE/X7_XM5_ljKI/AAAAAAAAyCY/VIJZnlgNEPQbhL9p3D0J3XsekBrGiNS3QCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-2.png" alt=""></a></p> -<p>After some research, it turns out you must wait a period of time (up to 12 hours in some cases) before you can make a second change to the Azure AD Sync status. This error simply means that we made a recent change to Azure AD Sync, and we must wait before making another change. To prove this, there is a “DirectorySynchronizationStatus” member for the Get-MsolCompanyInformation cmdlet. If we take a look at this member, we can see the status is “PendingDisabled”.</p> -<p><a href="https://lh3.googleusercontent.com/-0OBwKDDD5xQ/X7_X1bBxXjI/AAAAAAAAyCk/FyRlaMpCDT4aBe08TL_8sLiwUBnHkcPJQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-3.png" alt=""></a></p> -<p>Check the status of this periodically over the next 12 hours or so, and once it says “Enabled” or “Disabled”, you should be able to change the state once more.</p> - - - + http://localhost:1313/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ + I recently ran into a situation in my lab environment that required I resync all (2000+) user accounts to Azure AD. Though this sounds complex and daunting, its actually quite simple. T The basic steps involve disabling sync, and then removing the user objects. This can all be done with two PowerShell commands: 1) Set-MsolDirSyncEnabled -EnableDirSync $false 2) Get-MsolUser -All | Remove-MsolUser -force The account that you are currently running the commands as will not be removed. + Azure VM Scale Set &#8211; Get Instance IP Address - https://rnemeth90.github.io/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ + http://localhost:1313/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ Thu, 19 Nov 2020 18:07:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ - <p>If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal.</p> -<p>There are a few options we have for retrieving information about a VMSS and its instances without using the Azure Portal. We can use PowerShell or the Azure CLI. Being that I am constantly flipping between Windows and Linux, I will detail both here.</p> -<p>You will need to have the AZ module installed. To install this module, simple open PowerShell (as admin) and type in “Install-Module -Name az”. To get the IP address of the instances within a scale set, use the following script:</p> -<p><a href="https://github.com/rnemeth90/Get-VmssInstanceIpAddress">https://github.com/rnemeth90/Get-VmssInstanceIpAddress</a></p> -<p>You can also use the Azure CLI to obtain individual instance IP addresses. This method is much simpler than PowerShell, and only requires one line of code:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>az vmss nic list –resource-group myResourceGroup –vmss-name myVmss | grep –w “privateIpAddress” -</span></span></code></pre></div> - - + http://localhost:1313/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ + If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal. There are a few options we have for retrieving information about a VMSS and its instances without using the Azure Portal. + Azure Policy &#8211; Allowed Locations for Resource Deployment - https://rnemeth90.github.io/posts/2020-11-17-azure-policy-allowed-locations-for/ + http://localhost:1313/posts/2020-11-17-azure-policy-allowed-locations-for/ Tue, 17 Nov 2020 17:52:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-17-azure-policy-allowed-locations-for/ - <p>Azure Policy allows us to control what actions users can perform regarding creating and managing resources in Azure. We can define policies for naming standards, require that certain extensions be installed on virtual machines, audit various resources for certain configurations… the possibilities are endless.</p> -<p>In this article, well focus on defining what locations users can deploy resources in. To get started, login to the Azure Portal and search for “Policy”.</p> -<p><a href="https://lh3.googleusercontent.com/-7ao7r-Xj5Kk/X7QNKSrY3AI/AAAAAAAAx-8/xIUtw-pRL20pSMxsOaGUwnk-9XHSpup9ACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-4.png" alt=""></a></p> -<p>Click on “Definitions”. Here you will find several built-in definitions that can be applied to your resources. Definitions are a json template containing the logic for what you want to accomplish. It is worth investing some time to look through these built-in definitions.</p> -<p>In the “search” field, type in “location”. Then, click on the “Allowed Locations” definition.</p> -<p><a href="https://lh3.googleusercontent.com/-5FJ3EcMnG8k/X7QNP-1-5II/AAAAAAAAx_A/TH4cr4SxgbQiNVdoRlDyB_F4ukOV5bJvwCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-5.png" alt=""></a></p> -<p>Here you can see the json content of the definition. The “policyRule” section is the bread and butter of the definition. In this particular example, the policyRule states that if the location that the user is deploying a resource to is NOT a) in the list of allowed locations, b) global, or c) a b2c directory, then deny the deployment.</p> -<p><a href="https://lh3.googleusercontent.com/-WKsYDX4nao4/X7QNVcSEVJI/AAAAAAAAx_E/HIbPqLSHfBIjYRRZI27X7cLjStbnXlqaQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-6.png" alt=""></a></p> -<p>Next, click on “Assign”.</p> -<p><a href="https://lh3.googleusercontent.com/-Qg35QQcnGZY/X7QNarWcMbI/AAAAAAAAx_M/Et9yP9ZNyXEU1Ow8m5BwZG8RcTBaadInQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-7.png" alt=""></a></p> -<p>You can assign the policy to a subscription or resource group. You can also create exclusions in this same window, and enable or disable the policy.</p> -<p><a href="https://lh3.googleusercontent.com/-16qmOT43oKo/X7QNfuX4KVI/AAAAAAAAx_Q/_0wak5v2CCA2yIrwLalJgvhCnBCCEJcOQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-8.png" alt=""></a></p> -<p>Click “Next”, and on the Parameters page, choose the allowed locations from the drop down menu. Then click next.</p> -<p>Azure Policy has the capability to remediate non-compliant resources. An example would be having a policy that requires anti-virus be installed on all servers. If Azure Policy detected a server that did NOT have anti-virus installed, it would use a managed identity to install AV software on the server. This particular policy does not need a remediation action, so we will just click “Next” here.</p> -<p>On the Review + Create window, review the resource and then click “Create”.</p> -<p>Back on the Azure Policy blade, select “Assignments”. We can now see that our new policy is assigned.</p> -<p><a href="https://lh3.googleusercontent.com/-K8ofsNe1ALY/X7QNrf8dfkI/AAAAAAAAx_c/3R0DRk4LKWYcGP6-LJ3vgRUcUOQaZ6r3ACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-9.png" alt=""></a></p> -<p>Back on the “Overview” page, you can track compliance for the policy. We can see here that compliance for the “Allowed Locations” policy assignment has not yet been started. This typically takes an hour or so before the compliance state is updated.</p> -<p><a href="https://lh3.googleusercontent.com/-S-zq_cWBh7Y/X7QNvjMRUrI/AAAAAAAAx_k/CG194fTLqKIHqTNMmCyJzM4W9HJ_d6aPgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-10.png" alt=""></a></p> -<p>Click on the Policy to get a more detailed view of compliance, view the definition, edit the assignment, and even create exemptions.</p> -<p><a href="https://lh3.googleusercontent.com/-9sdnYSeQZ7A/X7QNzt8EEdI/AAAAAAAAx_o/3-2_eyPVjxIFSINg8IzEhKwZzWGUgf9NQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-11.png" alt=""></a></p> - - - + http://localhost:1313/posts/2020-11-17-azure-policy-allowed-locations-for/ + Azure Policy allows us to control what actions users can perform regarding creating and managing resources in Azure. We can define policies for naming standards, require that certain extensions be installed on virtual machines, audit various resources for certain configurations… the possibilities are endless. In this article, well focus on defining what locations users can deploy resources in. To get started, login to the Azure Portal and search for “Policy”. + Replicate an Azure VM Image Between Regions - https://rnemeth90.github.io/posts/2020-11-03-replicate-azure-vm-image-between-regions/ + http://localhost:1313/posts/2020-11-03-replicate-azure-vm-image-between-regions/ Tue, 03 Nov 2020 20:15:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-03-replicate-azure-vm-image-between-regions/ - <p>Let’s say you have a VM in Azure North Central. You created this VM from a custom image that you maintain in an Azure image repository. Now, what if you wanted to create that same VM in Azure South Central, and use the same reference image? A standard image repository is limited to the region that it exists in. The answer here is to create a Shared Image Library, add the image to it, and then configure the image to replicate to other Azure regions.</p> -<p>This article assumes you already have an image.</p> -<p>First, create a Shared Image Gallery in Azure. Browse to the Azure portal (<a href="https://portal.azure.com/">https://portal.azure.com</a>), and (from the home page) click “create a resource”.</p> -<p><a href="https://lh3.googleusercontent.com/-LQbh5w9zFN0/X6G5qBxrC1I/AAAAAAAAx5I/QH95DqgHJzUgkC5YhWqmQ_pOXmCygVHwQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-12.png" alt=""></a></p> -<p>Search for “Shared Image Gallery” and then click “Create”.</p> -<p>Configure a subscription, resource group, and then name the Shared Image Gallery and configure what region you want it to live in. You will want to create it in the same region as your standard image repository.</p> -<p><a href="https://lh3.googleusercontent.com/-61hBPxzwPzI/X6G5w_C7-iI/AAAAAAAAx5M/GVHvFpgE2WQwupil-OSd7nZ2nJEZRI0MgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-13.png" alt=""></a></p> -<p>If you want to assign some tags to this new resource, continue to the next page. Otherwise, click “Review + Create”.</p> -<p><a href="https://lh3.googleusercontent.com/-OCPyDsSbRYo/X6G52usmBSI/AAAAAAAAx5Q/nZJuX9YZzNsWU4aJwGNkZ5kulaXb5mcGgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-14.png" alt=""></a></p> -<p>On the final page, if the validation is successful, click “Create”.</p> -<p><a href="https://lh3.googleusercontent.com/-gCwUW-ntoKA/X6G56AAogVI/AAAAAAAAx5Y/wcUUn2_P68MNl5wCWIqQTYGRqEvJMJm6QCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-15.png" alt=""></a></p> -<p>It should take less than a minute to create the shared image gallery. Once its created, click “Go to resource”.</p> -<p><a href="https://lh3.googleusercontent.com/-mZQpi2f85MQ/X6G5-7FGFUI/AAAAAAAAx5c/vPOG47n736gp87Z2rftfjvL9OcGolOGxACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-16.png" alt=""></a></p> -<p>In the shared image gallery blade, click “Add new image definition”.</p> -<p><a href="https://lh3.googleusercontent.com/-qSWGjKuUMp4/X6G6CZsRAXI/AAAAAAAAx5g/-LYCx4Qmf98k2mbjM9CC-8mKVA-zp-8rACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-17.png" alt=""></a></p> -<p>On the next page, select the region where your existing image repository lives, give the image definition a name, and then fill out the rest of the information as needed. The publisher will typically be the name of your company/organization. The offer will typically be set to the name of the overall application, being that servers typically host one piece of an application (example: database servers vs. application servers). The SKU will typically be set to the name of the component within the application (for example, a web server or database server).</p> -<p><a href="https://lh3.googleusercontent.com/-4ZaK5D-Y0FE/X6G6G3n8KsI/AAAAAAAAx5k/jd18bOcFQ1kP62-0zE1Vuhwx6WpRnEyGwCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-18.png" alt=""></a></p> -<p>Next, configure an image version. This should use the typical semantic format used in software development (major version, minor version, patch level). I will typically substitute the patch level with the date the image was captured. Probably not a best practice, but something that has served me well in the past.</p> -<p>Next, select the source image. This will be the image that you are copying from your standard image repository. You can also configure an end of life date for the image version here if you wish. In the “Target Regions” section at the bottom, select the region where you plan to create the new VM. Also select the target storage account type.</p> -<p><a href="https://lh3.googleusercontent.com/-6F59gxbQ7ws/X6G6PI4qVeI/AAAAAAAAx5w/x2SCNG8PawMUZRQS6q55kAvgsOfD8bnPACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-19.png" alt=""></a></p> -<p>You can configure some publishing options and tags on the following pages. Though, it is not required. Click “Review + create”. <span style="mso-spacerun: yes;"> </span><span style="mso-spacerun: yes;"> </span>After the validation passes, click “Create”.</p> -<p><a href="https://lh3.googleusercontent.com/-CyzD7E88UVU/X6G6TQGRu6I/AAAAAAAAx54/2yHQrYIFUp8P8JyWMuEbsfFL47UW8Il0ACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-20.png" alt=""></a></p> -<p>This process will take a few minutes to complete. Once its finished, click on “go to resource”. You now have an image that is available to be deployed in the north central region or the south central region.</p> - - - + http://localhost:1313/posts/2020-11-03-replicate-azure-vm-image-between-regions/ + Let’s say you have a VM in Azure North Central. You created this VM from a custom image that you maintain in an Azure image repository. Now, what if you wanted to create that same VM in Azure South Central, and use the same reference image? A standard image repository is limited to the region that it exists in. The answer here is to create a Shared Image Library, add the image to it, and then configure the image to replicate to other Azure regions. + Reset GRUB/root Password for vCenter/PSC Appliance - https://rnemeth90.github.io/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ + http://localhost:1313/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ Sat, 31 Oct 2020 01:22:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ - <p>In Redhat/Fedora/Cent, GRUB can be protected by running the grub-md5-crypt command and pasting the outputted password hash into the grub.conf file. vSphere 6.0 password protects grub by default. If you change the root password in the VAMI, the GRUB password is changed to match. If you do not change the root password, the GRUB password is “vmware”.</p> -<p>To reset the GRUB password, we need to boot into a Cent or Redhat live CD. The ISO can be obtained here: <a href="https://www.centos.org/download/">https://www.centos.org/download/</a>. Its best to upload the ISO to a datastore that the appliance has access to.</p> -<p>Stop the appliance and attach the ISO:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image.png" alt=""></p> -<p>Be sure to select the “Connect at Power On” option. Boot the VM into the ISO and select the “Troubleshooting” option.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-1.png" alt=""> -Next, choose “Rescure a Red hat (or CentOS depending on your ISO) Enterprise Linux System”</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-2.png" alt=""></p> -<p>Select “Continue” to mount the VCSA 6.0’s root filesystem in Read/write mode under /mnt/sysimage. RHEL 7.2 is capable to detect the VCSA’s root volume and mounts it.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-3.png" alt=""></p> -<p>The VCSA root filesystem is mounted under /mnt/sysimage and you can now access (and modify) it using the shell. Navigate to /mnt/sysimage/boot and list the contents. You’ll see we now have access to the grub directory:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-4.png" alt=""></p> -<p>cd to the grub directory and list the contents. Look for a file called “menu.lst”. This file holds the grub boot loader password. Open this file with vi by typing “vi menu.lst”. Navigate to the line beginning with “password” using the arrow keys, and then type “dd” to remove the line.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-5.png" alt=""> -You can then save the file by pressing “:wq” (without quotes). You can now cat the file and see that the password has been removed.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-6.png" alt=""></p> -<p>Exit the shell (this will reboot the server). Detach the ISO and boot the appliance. Once the system is booted, stop the VCSA in the GRUB menu (by pressing the escape key during boot) to break the OS root password.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-7.png"></a> -Press “e” to edit the boot commands for the kernel.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-8.png" alt=""></p> -<p>Append “init=/bin/bash” to the line in this step and press enter.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-9.png" alt=""></p> -<p>Press “b” to boot the system.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-10.png" alt=""></p> -<p>You will now boot into a bash shell where you can set the root password.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-11.png" alt=""></p> -<p>Once this is done, exit the shell by typing “exit”. You can now boot the appliance and login with your new root password.</p> - - - + http://localhost:1313/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ + In Redhat/Fedora/Cent, GRUB can be protected by running the grub-md5-crypt command and pasting the outputted password hash into the grub.conf file. vSphere 6.0 password protects grub by default. If you change the root password in the VAMI, the GRUB password is changed to match. If you do not change the root password, the GRUB password is “vmware”. To reset the GRUB password, we need to boot into a Cent or Redhat live CD. + Deploy a New ADDS Forest on Server 2019 Core - https://rnemeth90.github.io/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ + http://localhost:1313/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ Sat, 31 Oct 2020 01:02:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ - <p>Prerequisites:</p> -<p>Change server name and IP address -Configure time settings and NTP</p> -<p>In this post we will be reviewing the basic installation of the Active Directory Domain Services role and setup of a new forest on Windows Server Core 2019.</p> -<p>To get started, login to your server with administrator privileges. You will first need to type in “powershell” in the cmd prompt to start powershell. Once you do that, type in the following command to install the Active Directory Domain Services role:</p> -<p><a href="https://lh3.googleusercontent.com/-LnSTbXjG2Hc/X5y3R3F-eWI/AAAAAAAAx2A/lWQBpA44Dmo-Jpbck2iPmgibU6z0DM1YwCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-12.png" alt=""></a></p> -<p>After installing the role, we’ll continue by creating a new ADDS Forest and promoting this server to the primary domain controller.</p> -<p>First, we’ll need to gather a password. This password will not be used for a domain user account. The local administrator on this server will become the domain administrator account for the domain. The password we’re gathering in the next step will be used for Directory Services Restore Mode (DSRM). DSRM is a recovery mode used to recover domain controllers that won’t boot up. We technically only need a password, not a username for this account.</p> -<p>Type in the following:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$cred = Get-Credential -</span></span></code></pre></div><p>In the username field for the credentials prompt below, just type in anything you want, as the value will not be used. This prompt will store our username/password in a variable object. We can then access the password within the credential object by typing:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$cred.password -</span></span></code></pre></div><p>We can see that this password is stored as a secure string object. Let’s continue on with the Directory Services installation.</p> -<p><a href="https://lh3.googleusercontent.com/-n-W0yvwr2Zs/X5y3X64NjZI/AAAAAAAAx2E/rx5urA7p_NMl3peX5g0J7Ax7biWwNADAgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-13.png" alt=""></a></p> -<p><a href="https://lh3.googleusercontent.com/-0k-aZrMhyGw/X5y3ckH10pI/AAAAAAAAx2I/FS56uvXCirAaBHKwWmIRQ4xIGU_jp_GFwCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-14.png" alt=""></a></p> -<p>Once we have our credential variable, we can install a new forest and domain controller using the command below. Let us break down what this cmd is doing:</p> -<p><a href="https://lh3.googleusercontent.com/-OF_HVfCPZIM/X5y3ijEA5YI/AAAAAAAAx2M/0vMV3CJczT8D3q5x8hzPAZVSL5DycplBACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-15.png" alt=""></a></p> -<p>Install-ADDSForest: The powershell cmdlet to create a new forest and domain controller</p> -<p>-DomainName: The domain name to be used for the forest</p> -<p>-DomainNetBiosName: The domain “Short name” to be used for the forest. This is the value used when you type in a username in the domainusername format. Example “myDomainbgates”.</p> -<p>-SafeModeAdministratorPassword: The value we captured in our credential prompt above. This is used for Directory Services Restore Mode. This mode can be accessed by pressing F8 while the server is booting. It is commonly used for recovering a failed domain controller.</p> -<p>-DatabasePath: The path for the Active Directory database. It’s a best practice to put this database on its own disk.</p> -<p>-LogPath: The directory for ADDS log files</p> -<p>-DomainMode: The domain functional level. The domain functional level specifies the attributes and capabilities available to objects within the domain. The higher the level you choose, the more features will be available to you.</p> -<p>-ForestMode: The forest functional level. Similar to the domain functional level but applies to the entire forest.</p> -<p>-InstallDNS: Install the DNS role alongside the ADDS role.</p> -<p>-WhatIf: This is a powershell “thing”. Most cmdlets have the “whatif” parameter. It basically allows you to run the cmdlet in “test” mode without actually making any changes to your environment. Once you’re happy with the output, you can remove the “whatif” parameter and run the command to install ADDS and promote this server to a domain controller.</p> - - - + http://localhost:1313/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ + Prerequisites: Change server name and IP address Configure time settings and NTP In this post we will be reviewing the basic installation of the Active Directory Domain Services role and setup of a new forest on Windows Server Core 2019. To get started, login to your server with administrator privileges. You will first need to type in “powershell” in the cmd prompt to start powershell. Once you do that, type in the following command to install the Active Directory Domain Services role: + Could not connect to VMware Directory Service via LDAP when Deploying New vCenter Appliance - https://rnemeth90.github.io/posts/2020-10-28-could-not-connect-to-vmware-directory/ + http://localhost:1313/posts/2020-10-28-could-not-connect-to-vmware-directory/ Wed, 28 Oct 2020 13:51:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-28-could-not-connect-to-vmware-directory/ - <p>Problem:</p> -<p>Deploying a brand new vCSA 6.7 appliance results in the following error during the second stage of the deployment.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h29_02.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h29_02.png" alt=""></a><span style="text-align: left;"> </span></p> -<p>Solution:</p> -<p>This problem is almost always caused by DNS resolution. Once you create the appropriate A and PTR record for your appliance on a LOCAL DNS server, you should be to successfully complete the deployment. Local DNS resolution is required, you cannot use a public DNS server while installing vCenter. For example, 8.8.8.8 will not work.</p> -<p>Since you have already completed Stage 1 of the deployment, you can login to the appliance via SSH and update the DNS settings. This will only work if you chose to enable SSH during Stage 2 of the deployment.</p> -<p>SSH to the appliance and run “/opt/vmware/share/vami/vami_config_net” (without quotes). Choose option 4 to update DNS settings and option 3 to update the hostname (if necessary). The deployment wizard states that a hostname is optional, but it is actually required. I have never had a successful deployment without specifying the hostname.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h33_18.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h33_18.png" alt=""></a></p> -<p>You can then verify the DNS settings have been updated in the resolve.conf:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h33_57.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h33_57.png" alt=""></a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_08h47_36.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_08h47_36.png" alt=""></a></p> - - - + http://localhost:1313/posts/2020-10-28-could-not-connect-to-vmware-directory/ + Problem: Deploying a brand new vCSA 6.7 appliance results in the following error during the second stage of the deployment. Solution: This problem is almost always caused by DNS resolution. Once you create the appropriate A and PTR record for your appliance on a LOCAL DNS server, you should be to successfully complete the deployment. Local DNS resolution is required, you cannot use a public DNS server while installing vCenter. For example, 8. + Cisco AnyConnect &#8211; VPN Establishment Capability from a Remote Desktop is Disabled - https://rnemeth90.github.io/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ + http://localhost:1313/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ Wed, 07 Oct 2020 13:28:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ - <p>I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution.</p> -<p><a href="https://lh3.googleusercontent.com/-BYApW8vZjV8/X33B2Or4D7I/AAAAAAAAxuY/hWQwpE-fqo4xInAsx9vyUvzDJXqxe68QQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-16.png" alt=""></a></p> -<p>Upon installation, AnyConnect pulls down a profile from the ASA containing several settings. This profile is in xml format and is located (on a Windows machine) at %programdata%CiscoCisco AnyConnect Secure Mobility ClientProfileAnyConnectProfile.xsd.</p> -<p>To resolve this issue and connect to your VPN, open this file with notepad (or any text editor, run as admin), search for the “WindowsVPNEstablishment” tag, and modify the value. The default value is “LocalUsersOnly”, you will need to change it to “AllowRemoteUsers”. Save and close the file, then restart the machine.</p> -<p>BEFORE:</p> -<p><a href="https://lh3.googleusercontent.com/-izGUUyhtWyM/X33Bh8YdqGI/AAAAAAAAxuQ/rBbXsqWhe5wZYoGmjXwyyidGmu1kCNVmgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-17.png" alt=""></a></p> -<p>AFTER:</p> -<p><a href="https://lh3.googleusercontent.com/-wFFu1JOXymQ/X33CVp0cImI/AAAAAAAAxug/fibXC6JHmkkilFtWv8641x20flapCibYACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-18.png" alt=""></a></p> - - - + http://localhost:1313/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ + I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution. Upon installation, AnyConnect pulls down a profile from the ASA containing several settings. This profile is in xml format and is located (on a Windows machine) at %programdata%CiscoCisco AnyConnect Secure Mobility ClientProfileAnyConnectProfile.xsd. To resolve this issue and connect to your VPN, open this file with notepad (or any text editor, run as admin), search for the “WindowsVPNEstablishment” tag, and modify the value. + Error When Reinstalling DirSync - https://rnemeth90.github.io/posts/2019-01-14-error-when-reinstalling-dirsync/ + http://localhost:1313/posts/2019-01-14-error-when-reinstalling-dirsync/ Mon, 14 Jan 2019 21:47:04 +0000 - - https://rnemeth90.github.io/posts/2019-01-14-error-when-reinstalling-dirsync/ - <p>Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/1.png" alt=""></a></p> -<p>I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do:</p> -<p>• Uninstall Windows Azure Active Directory Sync tool and reboot</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/2.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/2.png" alt=""></a></p> -<p>• Remove this directory and all subfolders: C:\Program Files\Windows\Azure Active Directory Sync</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/3.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/3.png" alt=""></a></p> -<p>• If you created a domain account to use for DirSync, remove it. Also remove the Office 365 account you created. -• Delete the Group accounts that the DirSync wizard created. Their names all begin with “FIM”</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/4.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/4.png" alt=""></a></p> -<p>• Uninstall MSSQL -• Delete the MSSQL directory: C:Program FilesMicrosoft SQL Server -• Reboot! -• You should be able to install and configure DirSync now.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/5.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/5.png" alt=""></a></p> - - - + http://localhost:1313/posts/2019-01-14-error-when-reinstalling-dirsync/ + Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process: I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do: + Active Directory Migration Toolkit &#8211; The RPC Server is Unavailable (hr=0x800706ba) - https://rnemeth90.github.io/posts/2018-08-21-active-directory-migration-toolkit-rpc/ + http://localhost:1313/posts/2018-08-21-active-directory-migration-toolkit-rpc/ Tue, 21 Aug 2018 17:34:00 +0000 - - https://rnemeth90.github.io/posts/2018-08-21-active-directory-migration-toolkit-rpc/ - <p>When migrating computer objects using the Active Directory Migration Tool, you may encounter the following error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_09.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_09.png" alt=""></a></p> -<p>In addition, the Migration Log may show the following error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_20.png" alt=""></a></p> -<p>This is typically caused by a host-side firewall. To resolve this, deploy a GPO to disable the Windows firewall prior to migrating the computer account. I like to create a special OU for computers (I typically name it “PreMigration”) that I will move computer objects to prior to migrating them. This OU will have two policies applied. One to disable the Windows Firewall and another to start the Remote Registry service. Both are required for the computer object to successfully migrate.</p> - + http://localhost:1313/posts/2018-08-21-active-directory-migration-toolkit-rpc/ + When migrating computer objects using the Active Directory Migration Tool, you may encounter the following error: In addition, the Migration Log may show the following error: This is typically caused by a host-side firewall. To resolve this, deploy a GPO to disable the Windows firewall prior to migrating the computer account. I like to create a special OU for computers (I typically name it “PreMigration”) that I will move computer objects to prior to migrating them. - Azure Site Recovery &#8211; VMware-to-Azure: Wrong IP address discovered for VM - https://rnemeth90.github.io/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ + http://localhost:1313/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ Tue, 21 Aug 2018 17:26:00 +0000 - - https://rnemeth90.github.io/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ - <p>When replicating virtual machines from VMware to Azure using Site Recovery, you may encounter an issue where the Configuration server discovers the wrong IP address for a VM. This can be caused by stale entries within the infrastructurevms MySQL table that is used by ASR to track VM attributes.</p> -<p>To resolve this issue, you first need to disable replication for the VM in the Azure Portal.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-21_13h20_26.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-21_13h20_26.png" alt=""></a></p> -<p>Next, login to your ASR Configuration Server and open a CMD prompt as administrator. Browse to the bin directory for your ASR installation. For example, in my case ASR is installed on the E: partition under the following directory:</p> -<p>E:\Program Files (x86)Microsoft Azure Site Recoveryhomesvsystemsbin</p> -<p>Type in this command to remove the VM from the ASR database (replace IP address with the IP of your VM):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-perl" data-lang="perl"><span style="display:flex;"><span>perl Unregister<span style="color:#f92672">-</span>ASRComponent<span style="color:#f92672">.</span>pl <span style="color:#f92672">-</span>IPAddress <span style="color:#ae81ff">10.0.0.4</span> <span style="color:#f92672">-</span>Component Source -</span></span></code></pre></div><p>That’s it. You should now be able to reconfigure replication for the VM, and ASR will discover the correct info about the VM.</p> - - - + http://localhost:1313/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ + When replicating virtual machines from VMware to Azure using Site Recovery, you may encounter an issue where the Configuration server discovers the wrong IP address for a VM. This can be caused by stale entries within the infrastructurevms MySQL table that is used by ASR to track VM attributes. To resolve this issue, you first need to disable replication for the VM in the Azure Portal. Next, login to your ASR Configuration Server and open a CMD prompt as administrator. + Azure AD Connect No-Start-Connection - https://rnemeth90.github.io/posts/2018-07-26-azure-ad-connect-no-start-connection/ + http://localhost:1313/posts/2018-07-26-azure-ad-connect-no-start-connection/ Thu, 26 Jul 2018 12:22:00 +0000 - - https://rnemeth90.github.io/posts/2018-07-26-azure-ad-connect-no-start-connection/ - <p>This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working.</p> -<p>After forcing the sync, I opened miisclient and noticed some strange errors. We sync multiple on-prem AD forests to Azure AD, and the status for one of them was “no-start-connection”. That error in itself does not seem significant to me. However, after clicking on the “failed-connection” link in the Connection Status pane, things became much more clear.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_05.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_05.png" alt=""></a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_18.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_18.png" alt=""></a></p> -<p>The domain controllers for the forest in question are in a datacenter that is geographically separated from the datacenter that our Azure AD Sync server lives in. The two sites are connected via a S2S VPN.</p> -<p>There was obviously some type of connection issue between our two datacenters. In my case, the issue was transient, and resolved itself after a few minutes. But if you’re experiencing this error message, check your L2/L3 connection. Also, verify DNS is working and someone didn’t make changes to your firewall(s). Just walk up or down the OSI model and you’ll eventually find the problem.</p> - - - + http://localhost:1313/posts/2018-07-26-azure-ad-connect-no-start-connection/ + This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working. After forcing the sync, I opened miisclient and noticed some strange errors. + Azure AD Connect Health: Latest Data is not Available in Azure Portal - https://rnemeth90.github.io/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ + http://localhost:1313/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ Wed, 18 Jul 2018 16:38:00 +0000 - - https://rnemeth90.github.io/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ - <p>I recently had to create a new Azure AD Connect server, and found that it was not able to report health status in the Azure Portal. After some troubleshooting/research, I was able to get the health status report working by registering the health agent on the server with Azure AD Health Services. Doing this involves running one PowerShell cmdlet on your AD Connect server and providing global administrator credentials.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_56.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_56.png" alt=""></a></p> -<p>First, let’s test the status of the agent communication:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_19.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_19.png" alt=""></a></p> -<p>If you do not receive any errors, that means the Azure AD Connect Health agent on your server is able to successfully communicate with the cloud service. Now, let’s register the agent:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_05.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_05.png" alt=""></a></p> -<p>You will be prompted for credentials. The credentials you provide need to be a global administrator account in your Azure AD tenant.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_42.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_42.png" alt=""></a></p> -<p>You should receive some output stating that the registration is successful (or it failed).</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h25_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h25_20.png" alt=""></a></p> -<p>Now, just go back to the Azure Portal and refresh the page. The message stating that the -“latest data is not available” should be gone.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h36_42.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h36_42.png" alt=""></a></p> - - - + http://localhost:1313/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ + I recently had to create a new Azure AD Connect server, and found that it was not able to report health status in the Azure Portal. After some troubleshooting/research, I was able to get the health status report working by registering the health agent on the server with Azure AD Health Services. Doing this involves running one PowerShell cmdlet on your AD Connect server and providing global administrator credentials. First, let’s test the status of the agent communication: + Removing a Forest from Azure AD Connect - https://rnemeth90.github.io/posts/2018-07-13-removing-forest-from-azure-ad-connect/ + http://localhost:1313/posts/2018-07-13-removing-forest-from-azure-ad-connect/ Fri, 13 Jul 2018 15:30:00 +0000 - - https://rnemeth90.github.io/posts/2018-07-13-removing-forest-from-azure-ad-connect/ - <p>In an organization with multiple Active Directory forests, you may want to sync objects from trusted forests. Adding trusted forests to Azure AD Sync is a simple process that I will likely cover in a future article. The focus of this post is the not-so-obvious process of removing a forest from Azure AD Connect. This can be a daunting and somewhat scary thing to do. Not fully understanding the process or having someone to guide you can leave you with thoughts like “what happens when I remove the forest from Azure AD Sync? Do on-premises objects get deleted? Are cloud objects deleted?”. I will try to answer these questions to the best of my ability and hopefully make the process simple and stress-free for you.</p> -<p>To get started, we first need to open PowerShell and disable the AD Sync scheduler. You can do this by running the “Set-ADSyncScheduler” cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h47_05.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h47_05.png" alt=""></a></p> -<p>This cmdlet is included in the ADSync PowerShell module. You may need to load the module prior to using the cmdlet:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Import-Module ADSync -</span></span></code></pre></div><p>The next step is to open FIM (miisclient) located in the install directory of Microsoft Azure AD Sync. By default, this is C:Program FilesMicrosoft Azure AD SyncUIShellmiisclient.exe. Once you have FIM open, click on the Connectors tab, then right click on the connector for the forest that you want to delete, and click “Delete”.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_26.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_26.png" alt=""></a></p> -<p>You will then be prompted, asking if you want to just delete the Connector Space, or delete the Connector and the Connector Space. The former open removes all data, but keeps the configuration in case you want to use it again later. The latter option deleted the data and the configuration. This open should only be used if you don’t plan on syncing the forest again.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_09.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_09.png" alt=""></a></p> -<p>The connector for the forest is now deleted, but what actually happens? Your on-premises objects do not get removed for the forest, and cloud objects <strong>are</strong> removed. Simple enough, right?</p> -<p>Now you just need to re-enable the AD Sync Scheduler with this cmdlet:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Set-ADSyncScheduler -SyncCycleEnabled $true -</span></span></code></pre></div><p>One last thing to mention… You may receive an email from the Microsoft Online Services Team stating that the identity synchronization failed due to a deletion threshold being met. By default, Azure AD Connect will not allow you to delete more than 500 objects in your cloud directory. This is to protect you from making a careless (potentially resume generating) mistake. The email will look something like this:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h56_04.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h56_04.png" alt=""></a></p> -<p>If you are certain that you want to proceed with deleting the objects, here are the steps:</p> -<ol> -<li> -<p>Disable the deletion threshold protection. Open PowerShell on your Azure AD Sync server and type in this cmdlet: Disable-ADSyncExportDeletionThreshold. You will be prompted for credentials, sign-in with an Azure AD Global Admin account.</p> -</li> -<li> -<p>Open FIM (miisclient), and click on the “Connectors” button at the top of the window. Right click on the connector of type “Windows Azure Active Directory”, and select “Run…”.</p> -</li> -</ol> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_39.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_39.png" alt=""></a></p> -<ol start="3"> -<li>Next, click Export and then click Ok.</li> -</ol> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_58.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_58.png" alt=""></a></p> -<ol start="4"> -<li> -<p>Allow the connector to run. This will take a few minutes. You can monitor the progress by clicking the Operations button.</p> -</li> -<li> -<p>Once this completes, you need to re-enable the deletion threshold. You can do this by running this cmdlet: <span style="background: #F9F9F9;"></p> -</li> -</ol> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Enable-ADSyncExportDeletionThreshold -DeletionThreshold <span style="color:#ae81ff">500</span>. -</span></span></code></pre></div><p>You will be prompted for credentials again. Just type in your Azure AD Global Admin creds. You can even lower the threshold if you’d like. I set mine to 100.</p> - - - + http://localhost:1313/posts/2018-07-13-removing-forest-from-azure-ad-connect/ + In an organization with multiple Active Directory forests, you may want to sync objects from trusted forests. Adding trusted forests to Azure AD Sync is a simple process that I will likely cover in a future article. The focus of this post is the not-so-obvious process of removing a forest from Azure AD Connect. This can be a daunting and somewhat scary thing to do. Not fully understanding the process or having someone to guide you can leave you with thoughts like “what happens when I remove the forest from Azure AD Sync? + Remove Stubborn PSC or vCenter Appliance from an SSO Domain - https://rnemeth90.github.io/posts/2017-11-08-remove-stubborn-psc-or-vcenter/ + http://localhost:1313/posts/2017-11-08-remove-stubborn-psc-or-vcenter/ Wed, 08 Nov 2017 07:56:00 +0000 - - https://rnemeth90.github.io/posts/2017-11-08-remove-stubborn-psc-or-vcenter/ - <p>While attempting to decommission one of our vCenter sites, I ran into an issue removing one of the PSCs. This site consisted of two PSCs and one vCenter appliance. I removed the first PSC from the SSO domain successfully, and then removed the vCenter appliance. Things became a little tricky during the removal of the final PSC. This PSC did not get removed even after running the cmsso-util command. This article will detail the steps I took in decommissioning the site, as well as removing the stubborn PSC.</p> -<p>First, we need to check if vCenter is currently using the PSC we plan on decommissioning. If it is, we need to use the cmsso-util command to redirect vCenter to a different PSC. Instructions for redirecting vCenter can be found here: <a href="https://kb.vmware.com/s/article/2113917?language=en_US">https://kb.vmware.com/s/article/2113917?language=en_US</a></p> -<p>To check what PSC your vCSA is currently pointing to, browse to the Advanced Settings for the vCSA in the vSphere Web Client. Filter by this key: config.vpxd.sso.admin.uri</p> -<p>To remove a PSC or vCSA from an SSO domain, connect to a PSC via SSH and run these commands:</p> -<p>To remove a PSC from the vSphere SSO domain:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>cmsso-util unregister –node-pnid psc01.ad.vcplab.local –username administrator@your<span style="color:#ae81ff">\_</span>domain<span style="color:#ae81ff">\_</span>name –passwd vCenter<span style="color:#ae81ff">\_</span>Single<span style="color:#ae81ff">\_</span>Sign<span style="color:#ae81ff">\_</span>On<span style="color:#ae81ff">\_</span>password -</span></span></code></pre></div><p>To remove a vCSA from the vSphere SSO domain:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>cmsso-util unregister –node-pnid vcsa.ad.vcplab.local –username administrator@your<span style="color:#ae81ff">\_</span>domain<span style="color:#ae81ff">\_</span>name –passwd vCenter<span style="color:#ae81ff">\_</span>Single<span style="color:#ae81ff">\_</span>Sign<span style="color:#ae81ff">\_</span>On<span style="color:#ae81ff">\_</span>password -</span></span></code></pre></div><p>After running these commands, delete the virtual appliances. You can also verify the appliances have been removed by browsing to Administration &gt; System Configuration &gt; Nodes in the vSphere Web Client.</p> -<p>If cmsso-util fails to remove any of the nodes, you can use this command to force the removal:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>vdcleavefed -h vcsa.ad.vcplab.local -u Administrator -w Passw0rd! -</span></span></code></pre></div><p>Upon successful completion, you should see something like this:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>/usr/lib/vmware-vmdir/bin/vdcleavefed -h vcsa.ad.vcplab.local -u administrator* password: -</span></span><span style="display:flex;"><span>vdcleavefd offline <span style="color:#66d9ef">for</span> server vcsa.ad.vcplab.local -</span></span><span style="display:flex;"><span>Leave federation cleanup <span style="color:#66d9ef">done</span> -</span></span></code></pre></div><p>When specifying the username, use the SSO admin (administrator). However, do not use the full UPN (<a href="mailto:administrator@vsphere.local">administrator@vsphere.local</a>). Doing so will cause the command to fail.</p> - - - + http://localhost:1313/posts/2017-11-08-remove-stubborn-psc-or-vcenter/ + While attempting to decommission one of our vCenter sites, I ran into an issue removing one of the PSCs. This site consisted of two PSCs and one vCenter appliance. I removed the first PSC from the SSO domain successfully, and then removed the vCenter appliance. Things became a little tricky during the removal of the final PSC. This PSC did not get removed even after running the cmsso-util command. This article will detail the steps I took in decommissioning the site, as well as removing the stubborn PSC. + Exchange 2016 Hybrid Deploy Check: Username or Password Invalid - https://rnemeth90.github.io/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ + http://localhost:1313/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ Tue, 07 Nov 2017 13:30:00 +0000 - - https://rnemeth90.github.io/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ - <p>These days, it seems every Microsoft product comes with its own unique set of head scratchers. Microsoft Exchange Server is no exception to this. I was installing Exchange 2016 earlier today, to be used as a hybrid configuration server for Office 365 (no local mailboxes). I downloaded the self depackaging executable from Microsoft, and attempted to install it. If you currently have a hybrid configuration (which we did, with Exchange 2010), the Exchange 2016 installer will detect this and run some tests to verify that the Office 365 tenant is ready for Exchange 2016 (more info here: <a href="https://technet.microsoft.com/en-us/library/ms.exch.setup.hybridconfigurationstatuspage(v=exchg.160).aspx">https://technet.microsoft.com/en-us/library/ms.exch.setup.hybridconfigurationstatuspage(v=exchg.160).aspx</a>). You’ll be prompted for Office 365 credentials (the user must have the Organization Management role). Seems simple enough, right? Wrong.</p> -<p>After typing in the username and <em>pasting</em> the password into the password field, setup came back with an error message stating the username or password was wrong. I then clicked the back button, and it crashed. I ran through this process a few more times, all with the same outcome. I even rebooted the server, which (in my opinion) should never be the resolution to a software problem. I looked through setup logs and found no indication of what the problem could be…</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2017/11/2017-11-07_12h57_08.png" alt=""></p> -<p>It was on the fourth try that I typed in the password, and this seemed to work. I didn’t receive any error messages about the credentials being wrong. The Exchange setup seemed to continue on successfully. However, it then failed with a different error:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2017/11/2017-11-07_13h12_02.png" alt=""></p> -<p>I again looked through the setup logs and found that this error happened anytime setup tried to run the “Get-OrganizationConfig” cmdlet. After troubleshooting for a little while, and no resolution in sight, I turned to Google. One of the posts I came across said that this is a bug in the Exchange installer, and to try and use the Cumulative Update installer instead. Apparently, with Exchange 2016, the Cumulative Update installer’s include all of the Exchange binaries, not just the updated binaries. I downloaded the installer for CU7 (all 6 gigabytes of it…) and successfully installed Exchange 2016. Hope this helps anyone out there struggling with this.</p> - - - + http://localhost:1313/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ + These days, it seems every Microsoft product comes with its own unique set of head scratchers. Microsoft Exchange Server is no exception to this. I was installing Exchange 2016 earlier today, to be used as a hybrid configuration server for Office 365 (no local mailboxes). I downloaded the self depackaging executable from Microsoft, and attempted to install it. If you currently have a hybrid configuration (which we did, with Exchange 2010), the Exchange 2016 installer will detect this and run some tests to verify that the Office 365 tenant is ready for Exchange 2016 (more info here: https://technet. + Migrate Windows Deployment Services to New Server - https://rnemeth90.github.io/posts/2017-06-27-migrate-windows-deployment-services-to-new-server/ + http://localhost:1313/posts/2017-06-27-migrate-windows-deployment-services-to-new-server/ Tue, 27 Jun 2017 09:21:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-27-migrate-windows-deployment-services-to-new-server/ - <p>We have been making a great effort to move all of our internal services to Windows Server 2016. This past week, it was WDS’ turn to get migrated. Migrating this role is extremely simple. Here are the steps that I took:</p> -<ol> -<li>Create new server and install WDS role.</li> -<li>Stop WDS Service on old server</li> -<li>Stop WDS Service on new server</li> -<li>Use my “Copy-Files” PowerShell script (Available Here: <a href="https://gallery.technet.microsoft.com/scriptcenter/Copy-Files-17cba2ae">Copy-Files.ps1</a>) to copy RemoteInstall Share to new server</li> -<li>Start WDS Service on new Server</li> -<li>Shutdown old WDS Server completely</li> -<li>Update option 66/67 in DHCP scopes to reflect new WDS Server</li> -<li>Update any appropriate DNS records</li> -</ol> -<p>Note:</p> -<p>If you are unable to start the WDS service, delete the WDS database and logs from the old server located at &lt;drive letter&gt;:RemoteInstallStoresMetadata*.*. You should be able to start the service after deleting these files.</p> -<p>Simple enough! 🙂</p> - - - + http://localhost:1313/posts/2017-06-27-migrate-windows-deployment-services-to-new-server/ + We have been making a great effort to move all of our internal services to Windows Server 2016. This past week, it was WDS’ turn to get migrated. Migrating this role is extremely simple. Here are the steps that I took: Create new server and install WDS role. Stop WDS Service on old server Stop WDS Service on new server Use my “Copy-Files” PowerShell script (Available Here: Copy-Files.ps1) to copy RemoteInstall Share to new server Start WDS Service on new Server Shutdown old WDS Server completely Update option 66/67 in DHCP scopes to reflect new WDS Server Update any appropriate DNS records Note: + New Script: BulkAdd-SpamFilterWhitelist.ps1 - https://rnemeth90.github.io/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ + http://localhost:1313/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ Mon, 26 Jun 2017 22:16:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ - <p>This script is capable of adding a list of domains to an Exchange Online Spam Filter policy. It can be downloaded from TechNet or Github.</p> -<p><a href="https://github.com/rnemeth90/PowerShell/blob/master/BulkAdd-SpamFilterWhitelist.ps1">Github</a></p> -<p><a href="https://gallery.technet.microsoft.com/BulkAdd-SpamFilterWhitelist-2d2b596a">TechNet</a></p> - + http://localhost:1313/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ + This script is capable of adding a list of domains to an Exchange Online Spam Filter policy. It can be downloaded from TechNet or Github. Github TechNet - Windows 8 File History - https://rnemeth90.github.io/posts/2017-06-22-windows-8-file-history-windows-8-file-history/ + http://localhost:1313/posts/2017-06-22-windows-8-file-history-windows-8-file-history/ Thu, 22 Jun 2017 22:42:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-22-windows-8-file-history-windows-8-file-history/ - <p>File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. To begin using it, connect an external drive and search for File History on the Start Screen:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2014-11-15_14h19_47.png" alt=""></p> -<p>After opening File History, you will see this screen:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2014-11-15_14h20_32.png" alt=""></p> -<p>To enable File History, click the ‘Turn On’ button. You can select the drive you want to use by clicking ‘Select Drive’ on the left hand side from this same screen. The first time you enable File History, it will create a full backup of all files on your computer, except for files that you do not access (system files), and files you have chosen to exclude. From then on, it will create a versioned copy of every file that has changed since the last backup.</p> -<p>You can use a locally attached drive or a network share for File History. To choose how often File History backs up files; choose ‘Advanced Settings’. From here you can also choose how much space on the drive is used, and how long saved versions of files should be kept.</p> -<p>When the total space allocated to File History has been used, the feature will delete the oldest versions of files to make room for newer versions.</p> - - - + http://localhost:1313/posts/2017-06-22-windows-8-file-history-windows-8-file-history/ + File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. + How to Permanently Remove Office 365 Users - https://rnemeth90.github.io/posts/2017-06-20-how-to-permanently-remove-office-365-users/ + http://localhost:1313/posts/2017-06-20-how-to-permanently-remove-office-365-users/ Tue, 20 Jun 2017 18:13:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-20-how-to-permanently-remove-office-365-users/ - <p>After deleting a user in Office 365, their account is moved to a ‘recycle bin’ for 30 days. This allows the user account to be easily recovered. This can often cause issues when attempting to recreate a mailbox while a hybrid configuration is in place.</p> -<p>To permanently delete the user within Office 365, first delete the user in the Office 365 Admin Portal or using Powershell. Then, connect to your Azure Active Directory environment with Powershell using the “Connect-MsolService” cmdlet.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h06_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h06_20.png" alt=""></a></p> -<p>To see a list of user accounts currently in the recycle bin, run this cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h09_47.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h09_47.png" alt=""></a></p> -<p>Then, to permanently delete all accounts in the recycle bin, run this cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h10_16.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h10_16.png" alt=""></a></p> -<p>To remove a specific user, run this cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h11_15.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h11_15.png" alt=""></a></p> - - - + http://localhost:1313/posts/2017-06-20-how-to-permanently-remove-office-365-users/ + After deleting a user in Office 365, their account is moved to a ‘recycle bin’ for 30 days. This allows the user account to be easily recovered. This can often cause issues when attempting to recreate a mailbox while a hybrid configuration is in place. To permanently delete the user within Office 365, first delete the user in the Office 365 Admin Portal or using Powershell. Then, connect to your Azure Active Directory environment with Powershell using the “Connect-MsolService” cmdlet. + Access is Denied When Attempting to Delete a Dynamic Distribution Group - https://rnemeth90.github.io/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ + http://localhost:1313/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ Mon, 12 Jun 2017 13:41:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ - <p>You may receive the error below when attempting to delete a dynamic distribution group.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-12_09h29_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-12_09h29_20.png" alt=""></a></p> -<p>To resolve this, open ADUC and show advanced features (Click View &gt; Advanced Features). Then find the object for the dynamic distribution group and open the properties window. Browse to the “Object” tab and uncheck the “Protect object from accidental deletion” box. Wait for ADDS to replicate or force replication yourself.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-12_09h34_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-12_09h34_20.png" alt=""></a></p> -<p>Go back to the ECP and you should be able to delete the group.</p> - + http://localhost:1313/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ + You may receive the error below when attempting to delete a dynamic distribution group. To resolve this, open ADUC and show advanced features (Click View &gt; Advanced Features). Then find the object for the dynamic distribution group and open the properties window. Browse to the “Object” tab and uncheck the “Protect object from accidental deletion” box. Wait for ADDS to replicate or force replication yourself. Go back to the ECP and you should be able to delete the group. - Running vSphere in VMware Workstation 12 - https://rnemeth90.github.io/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/ + http://localhost:1313/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/ Mon, 29 May 2017 01:09:00 +0000 - - https://rnemeth90.github.io/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/ - <p>In this post I’ll be walking through how to run a vSphere lab in VMware Workstation. I recently decided to obtain VCP6-DCV. Rather than driving up my electric bill like I’ve done in the past using physical servers, I’m attempting to run the entire lab on my workstation and a Synology NAS.</p> -<p>If you’ve ever installed ESXi, installing it in Workstation will be a familiar process for you. VMware tools is included in the installation disc, which makes installing ESXi in Workstation dramatically easier than it used to be. . The process is very simple, so I won’t be going through those steps here unless someone asks me to in the comments. I also will not be going through the process of installing Windows Server or configuring a domain controller/DNS/DHCP, as I am sure you have done so in the past if you are reading this.</p> -<p>So that really only leaves us with installing vCenter. Most of the blogs I found for installing vCenter in VMware Workstation 12 were not accurate, and often left me with a broken installation. The process is somewhat straight-forward when deploying from the OVA. Let’s get started.</p> -<p>First, download the OVA for vCenter here: <a href="https://my.vmware.com/web/vmware/details?productId=614&amp;downloadGroup=VC650">Download vCenter</a></p> -<p>Once the download has completed, click File &gt; Open in Workstation. Browse to the OVA, then give your new VM a name and location if necessary. Accept the EULA when prompted.</p> -<p>Be sure to read it! 😎</p> -<p>Once the OVA finishes importing, do not power on the VM! There is some customization we need to do first. Close Workstation if it is open. Browse to the location on your PC that you imported the VM to. I’m using a Windows OS, so I will use File Explorer. Open the .VMX file (use Notepad or another text editor):</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-28_21h00_04.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-28_21h00_04.png" alt=""></a></p> -<p>This is the configuration file for your virtual machine. We can use it to customize the name, IPv4/6 details, DNS domain, etc. Scroll down to the last line of text, and paste this in:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>guestinfo.cis.vmdir.password <span style="color:#f92672">=</span> “vmware!” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.addr.family <span style="color:#f92672">=</span> “ipv4” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.addr <span style="color:#f92672">=</span> “10.0.0.15” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.prefix <span style="color:#f92672">=</span> “24” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.mode <span style="color:#f92672">=</span> “static” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.dns.servers <span style="color:#f92672">=</span> “10.0.0.10” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.gateway <span style="color:#f92672">=</span> “10.0.0.1” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.root.passwd <span style="color:#f92672">=</span> “vmware!” -</span></span></code></pre></div><p>Customize the above code to your needs. You will likely need to change the IPv4 details. Save the .VMX file and close your text editor. Now you can power on the virtual machine, and vCenter will run through the installation process. The installation can take around 10-15 minute in my experience. You may see generic login screens during the installation of Photon, do not login or interrupt the installation. Once it is complete, you should see the DCUI below:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h11_00.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h11_00.png" alt=""></a></p> -<p>You should now be able to browse to the IP address or DNS name of your vCenter server. Once you complete the configuration, you can login and see the page below: -<a href="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h10_39.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h10_39.png" alt=""></a></p> -<p>In my lab I am running 3 ESXi hosts, 1 Windows Server, and one vCenter server. Plenty to study for the VCP lab.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h11_31.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h11_31.png" alt=""></a></p> -<p>Good luck and be sure to leave a comment if you have any questions!</p> - - - + http://localhost:1313/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/ + In this post I’ll be walking through how to run a vSphere lab in VMware Workstation. I recently decided to obtain VCP6-DCV. Rather than driving up my electric bill like I’ve done in the past using physical servers, I’m attempting to run the entire lab on my workstation and a Synology NAS. If you’ve ever installed ESXi, installing it in Workstation will be a familiar process for you. VMware tools is included in the installation disc, which makes installing ESXi in Workstation dramatically easier than it used to be. + WSUS: Update Files Not Downloading (Content File Download Failed) - https://rnemeth90.github.io/posts/2016-11-18-wsus-update-files-not-downloading/ + http://localhost:1313/posts/2016-11-18-wsus-update-files-not-downloading/ Fri, 18 Nov 2016 15:13:00 +0000 - - https://rnemeth90.github.io/posts/2016-11-18-wsus-update-files-not-downloading/ - <p>This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-18_10h02_21.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-18_10h02_21.png" alt=""></a></p> -<p>You may also see this event (or similar) in the Event Log.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_32.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_32.png" alt=""></a></p> -<p>This problem is caused by not specifying a valid path when assigning the WSUS content drive when first installing the role. The first time you load the WSUS console after installing the role, you will be prompted to specify the path to store Windows Update files. WSUS does not like to have its content directory be the root of a partition. For example, if I were to specify “e:” as the path for the Windows Update content, the wizard would give you an error message stating that the path is not valid. However, it doesn’t prompt you to re-enter the path if you click close. The WSUS console opens immediately after and that invalid path is where WSUS will try to store your update files. This is and has been a known bug for a while and needs to be addressed by Microsoft. Evidence of the invalid path can be found in the registry under:</p> -<p>HKLMSoftwareMicrosoftUpdate ServicesServerSetupContentDir</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_44.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_44.png" alt=""></a></p> -<p>If you come across this problem, you can change the ContentDir above to a valid path. Keep in mind that it cannot be the root of a partition. You need to specify a drive letter with a subfolder (eg: e:wsus).</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h54_54.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h54_54.png" alt=""></a></p> -<p>The other option is to reinstall the WSUS role. If you remove the role, the WID database is not removed, unless you remove that role as well (or manually delete the database). This means that when you reinstall the WSUS role, it will be able to use that same database and any clients that have contacted the WSUS server will immediately show up in the console. The same is true for update metadata. The new WSUS installation will still have the same approvals, denials, etc. as the old installation.</p> -<p>Regardless of what option you choose, I suggest rebooting the server after you make the changes.</p> - - - + http://localhost:1313/posts/2016-11-18-wsus-update-files-not-downloading/ + This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates: You may also see this event (or similar) in the Event Log. This problem is caused by not specifying a valid path when assigning the WSUS content drive when first installing the role. The first time you load the WSUS console after installing the role, you will be prompted to specify the path to store Windows Update files. + WSUS: An error occurred trying to connect the WSUS server - https://rnemeth90.github.io/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ + http://localhost:1313/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ Thu, 10 Nov 2016 15:18:00 +0000 - - https://rnemeth90.github.io/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ - <p>Ran into this error message when configuring a new WSUS server:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h56_00.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h56_00.png" alt=""></a></p> -<p>Restarted the WSUS, WID, and IIS services to no avail. I even rebooted the server. The WSUS console would work for a short period of time, and then would randomly stop working.</p> -<p>I found that the WSUS app pool in IIS was being disabled anytime new clients connected to the server. I believe this was because the app pool was running out of usable memory.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h28_56.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h28_56.png" alt=""></a></p> -<p>You can manually start the app pool in IIS, but it will continue to crash.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h56_48.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h56_48.png" alt=""></a></p> -<p>The solution for me was to increase the memory limit available for the application pool:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h57_38.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h57_38.png" alt=""></a></p> -<p>By default it is only configured to use just under 2 GBs. I reconfigured it to use up to 4 GB and the WSUS console has not crashed since. After re-configuring the memory for the application pool, run an IIS reset or reboot the server.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h31_40.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h31_40.png" alt=""></a></p> -<p>UPDATE: Setting the Private Memory Limit to “0” will allow the application pool to use whatever amount of memory it needs.</p> - - - + http://localhost:1313/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ + Ran into this error message when configuring a new WSUS server: Restarted the WSUS, WID, and IIS services to no avail. I even rebooted the server. The WSUS console would work for a short period of time, and then would randomly stop working. I found that the WSUS app pool in IIS was being disabled anytime new clients connected to the server. I believe this was because the app pool was running out of usable memory. + WDS Service: The Service did not respond in a timely fashion - https://rnemeth90.github.io/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ + http://localhost:1313/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ Thu, 10 Nov 2016 02:19:00 +0000 - - https://rnemeth90.github.io/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ - <p>This was a new one for me. Usually WDS is rock solid and it just works.</p> -<p>Anyway, I was getting ready to deploy some servers in my lab and found that I couldn’t get WDS to start on my deployment server. I got this error message when trying to start the service:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h02_29.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h02_29.png" alt=""></a></p> -<p>I then tried to start the service from the Services console and got this error message:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h02_42.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h02_42.png" alt=""></a></p> -<p>“This was just working yesterday”, I said to myself. What could possibly have happened since yesterday evening that could cause this? I looked in the event log and after scrolling through the Administrative Events, I found this:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h04_33.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h04_33.png" alt=""></a></p> -<p>The solution was so obvious it was staring me in the face, but I wanted to verify first. So I fired up a cmd prompt and ran netstat, and found this:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h06_14.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h06_14.png" alt=""></a></p> -<p>I had installed DHCP on this server the night before and totally forgot about it. Anyway, the solution was simple. I just needed to tell the WDS service to not listen on port 67. To do that, just open the WDS server properties and got to the “DHCP” tab. Then check the box next to “Do not listen on DHCP Ports”.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h08_04.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h08_04.png" alt=""></a></p> -<p>I was then able to start the DHCP service.</p> - - - + http://localhost:1313/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ + This was a new one for me. Usually WDS is rock solid and it just works. Anyway, I was getting ready to deploy some servers in my lab and found that I couldn’t get WDS to start on my deployment server. I got this error message when trying to start the service: I then tried to start the service from the Services console and got this error message: “This was just working yesterday”, I said to myself. + Script to Move All Disabled AD Objects to a Specified OU - https://rnemeth90.github.io/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ + http://localhost:1313/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ Thu, 06 Oct 2016 03:03:00 +0000 - - https://rnemeth90.github.io/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ - <p>The title says it all. This script will move all disabled AD objects to a specified OU. This script accepts parameters that will allow you to specify whether you want to move Users or Computers and the destination OU. It also accepts a “test mode” parameter that will run the script and output the results, without actually modifying Active Directory.</p> -<p>This is revision 1 of the script. There are still several improvements I would like to make, including better error handling and recovery.</p> -<p>If you have any suggestions or requests, please leave a comment.</p> -<p><a href="https://drive.google.com/open?id=0B2K6VOnt6zeXMVFleWZISHZBTnc">Download Here</a></p> - + http://localhost:1313/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ + The title says it all. This script will move all disabled AD objects to a specified OU. This script accepts parameters that will allow you to specify whether you want to move Users or Computers and the destination OU. It also accepts a “test mode” parameter that will run the script and output the results, without actually modifying Active Directory. This is revision 1 of the script. There are still several improvements I would like to make, including better error handling and recovery. - Exchange 2013: Error 0x80070070 While Adding DAG Member - https://rnemeth90.github.io/posts/2016-10-04-exchange-2013-error-0x80070070-while/ + http://localhost:1313/posts/2016-10-04-exchange-2013-error-0x80070070-while/ Tue, 04 Oct 2016 00:21:00 +0000 - - https://rnemeth90.github.io/posts/2016-10-04-exchange-2013-error-0x80070070-while/ - <p>Error: A server-side database availability group administrative operation failed. Error Failed to add or remove the Failover-Clustering feature. Error: The request to add or remove features on the specified server failed. A DISM session could not be opened. An error occurred accessing the temporary folder C:WindowsTEMP57ACE2DE-4CD2-4F5F-B7A0-93D867A89A12. Ensure that the path to the temporary folder exists and that you have Read/Write permissions on the folder. Error: 0x80070070</p> -<p>Solution: I was attempting to remotely add the DAG member from the ECP on my workstation. I logged into the server and found that the system drive was nearly full (~100MB free). Luckily this mailbox server was a virtual machine, and I was able to quickly expand the drive using VMM. After doing this I was able to successfully add the mailbox server to the DAG.</p> - + http://localhost:1313/posts/2016-10-04-exchange-2013-error-0x80070070-while/ + Error: A server-side database availability group administrative operation failed. Error Failed to add or remove the Failover-Clustering feature. Error: The request to add or remove features on the specified server failed. A DISM session could not be opened. An error occurred accessing the temporary folder C:WindowsTEMP57ACE2DE-4CD2-4F5F-B7A0-93D867A89A12. Ensure that the path to the temporary folder exists and that you have Read/Write permissions on the folder. Error: 0x80070070 Solution: I was attempting to remotely add the DAG member from the ECP on my workstation. - Script for Setting the License for Multiple Office 365 User Accounts - https://rnemeth90.github.io/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ + http://localhost:1313/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ Mon, 11 Apr 2016 01:25:00 +0000 - - https://rnemeth90.github.io/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ - <p>A script for setting the Office 365 license for multiple users. Requires a CSV file named users.csv. This file must in the same directory as the script. The CSV file must contain three columns. The title of the columns should be UPN, UsageLocation, and SKU.</p> -<p><a href="https://drive.google.com/open?id=0B2K6VOnt6zeXZ2Z6OFZhZVoyenc">BulkSet-MsolUserLicense.ps1</a></p> - + http://localhost:1313/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ + A script for setting the Office 365 license for multiple users. Requires a CSV file named users.csv. This file must in the same directory as the script. The CSV file must contain three columns. The title of the columns should be UPN, UsageLocation, and SKU. BulkSet-MsolUserLicense.ps1 - The User Profile Service service failed the logon - https://rnemeth90.github.io/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ + http://localhost:1313/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ Wed, 30 Dec 2015 10:38:00 +0000 - - https://rnemeth90.github.io/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ - <p>One of my clients had a really strange issue the other day. He has a domain admin account in his domain and was not able to login to a server that I recently built. The server was an Exchange 2013 box, and was used in Coexistence mode to migrate his company from an Exchange 2007 box.</p> -<p>He was getting this error message when attempting to login:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/12/2015-12-30_09h38_53.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/12/2015-12-30_09h38_53.png" alt=""></a></p> -<p>This is a classic error message that I’m sure most technicians have seen before. Usually the resolution is to go into the registry and rename the user profile key to have a “.bak” extension and then do some other magic. However, this time, that was not the case. I looked in the registry and didn’t even see a reg key for his profile. I then looked in the c:users folder and didn’t see a folder for his profile. Strange…</p> -<p>So what exactly was happening? Well, I took a look at the Event Viewer and found this error message:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/12/2015-12-30_09h34_06.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/12/2015-12-30_09h34_06.png" alt=""></a></p> -<p>I browsed to the file referenced in the error message and deleted it. Walla! He was able to login with his admin account. I’m not sure why this file was in the default user profile. It has something to do with Customer Experience Improvement Program:</p> -<p><a href="http://www.nextofwindows.com/what-is-sqmdata-and-sqm-file-in-windows-7-and-how-to-delete-them">http://www.nextofwindows.com/what-is-sqmdata-and-sqm-file-in-windows-7-and-how-to-delete-them</a></p> - - - + http://localhost:1313/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ + One of my clients had a really strange issue the other day. He has a domain admin account in his domain and was not able to login to a server that I recently built. The server was an Exchange 2013 box, and was used in Coexistence mode to migrate his company from an Exchange 2007 box. He was getting this error message when attempting to login: This is a classic error message that I’m sure most technicians have seen before. + Azure AD Connect Password Sync &#8211; Disabled and Grayed Out - https://rnemeth90.github.io/posts/2015-10-15-azure-ad-connect-password-sync-disabled/ + http://localhost:1313/posts/2015-10-15-azure-ad-connect-password-sync-disabled/ Thu, 15 Oct 2015 10:18:00 +0000 - - https://rnemeth90.github.io/posts/2015-10-15-azure-ad-connect-password-sync-disabled/ - <p>Ran into a problem earlier with the new Azure AD Connect Wizard. We had configured the wizard and synced around 500 AD accounts. However, password sync was not working. I opened the wizard to confirm the configuration and found that “Password Hash Synchronization” was disabled. It was greyed out and could not be enabled.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_08h43_18.jpg"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_08h43_18.jpg" alt=""></a></p> -<p>I called Microsoft and worked for a couple hours with a technician to resolve the issue. Thought I should post the resolution here in case anyone else encounters this.</p> -<p>You can enable password sync by running the following script:</p> -<p>Import-Module ADSync</p> -<p>$adConnector = “&lt;Local AD Connector Name&gt;”</p> -<p>$aadConnector = “&lt;Azure AD Connector Name&gt;”</p> -<p>Set-ADSyncAADPasswordSyncState -ConnectorName $aadConnector –Enable $true</p> -<p>Set-ADSyncAADPasswordSyncConfiguration -SourceConnector $adConnector -TargetConnector $aadConnector -Enable $true</p> -<p>get-ADSyncAADPasswordSyncConfiguration -sourceconnector $adConnector</p> -<p>You need to set the value of the $adConnector and $aadConnector variables with the names of your Connectors found in the MIISClient.</p> -<p>Open the MIISClient by browsing to:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_09h39_42.jpg"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_09h39_42.jpg" alt=""></a></p> -<p>Right click on MIISClient.exe and click “Run As Administrator”.</p> -<p>You can obtain the names of your connectors in by going to the Connectors tab and looking at the Names column. There are two values here that you need to pay attention to. The Windows Azure Active Directory connector is your Azure Connector (obviously), and the other connector is your on-prem connector.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_09h39_31.jpg"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_09h39_31.jpg" alt=""></a></p> -<p>Now that you have the names, just plug them into the script and run it. You can go back to the Azure AD Connect Wizard and verify that password sync is enabled. You can also go to the Event Viewer -&gt; Application log and look for events 576 and 577. These two events are related to password sync and should show you all AD accounts that have successfully synced passwords.</p> -<p>You can force a sync by going to this location and running “DirectorySyncClientCmd.exe”.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_10h21_12.jpg"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_10h21_12.jpg" alt=""></a></p> - - - + http://localhost:1313/posts/2015-10-15-azure-ad-connect-password-sync-disabled/ + Ran into a problem earlier with the new Azure AD Connect Wizard. We had configured the wizard and synced around 500 AD accounts. However, password sync was not working. I opened the wizard to confirm the configuration and found that “Password Hash Synchronization” was disabled. It was greyed out and could not be enabled. I called Microsoft and worked for a couple hours with a technician to resolve the issue. Thought I should post the resolution here in case anyone else encounters this. + Finding All Mailboxes with a Forwarding Address in Exchange 2003 - https://rnemeth90.github.io/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ + http://localhost:1313/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ Mon, 07 Sep 2015 23:13:00 +0000 - - https://rnemeth90.github.io/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ - <p>Believe it or not, the MSP I work for still has a client who is using Exchange 2003 as their primary email service. Despite several attempts at convincing them of the power of Office 365, they refuse to migrate. Last week the CFO contacted me and requested we provide them with a report of all users who have their email forwarded to another mailbox. “Ok, no problem.” I said helpfully as the client informed me of their request (at the time I didn’t even think about them having Exchange 2003…). I figured I would just connect to their server and do some quick PowerShell magic, and that would be it. Quick and painless, right? Wrong.</p> -<p>I did the RDP dance and got connected to their server, and my jaw just about hit the floor when I couldn’t find the Exchange Management Shell! I asked around the office to see if any of the other guys could help, but no one knew what to do. However, after talking with one of the guys, I remembered that this is Active Directory we are dealing with. There are objects, and those objects have attributes. The mailboxes/user accounts are objects, and those objects have attributes. So what attribute is it that controls forwarding addresses? I manually found one of the users who had a forwarding address configured. Then I opened up Active Directory Users and Computers, opened up her account properties, and went to the Attribute Editor tab. I filtered for attributes that have values and was able to see the email address that her mail was forwarding to. This was the “altRecipient” attribute.</p> -<p>I then did an “Advanced” search in Active Directory Users and Computers for any objects that have the “altRecipient” attribute configured, like so:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/09/ExchangeForwarding.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/09/ExchangeForwarding.png" alt=""></a></p> -<p>This search showed me all of the mailboxes that have an alternate recipient (forwarding address) configured. Not sure if there is another way to obtain this information, but this is the way that worked for me. Hopefully this article is able to help someone in the same situation.</p> - + http://localhost:1313/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ + Believe it or not, the MSP I work for still has a client who is using Exchange 2003 as their primary email service. Despite several attempts at convincing them of the power of Office 365, they refuse to migrate. Last week the CFO contacted me and requested we provide them with a report of all users who have their email forwarded to another mailbox. “Ok, no problem.” I said helpfully as the client informed me of their request (at the time I didn’t even think about them having Exchange 2003…). - Script for Querying All AD Computers Time Source - https://rnemeth90.github.io/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ + http://localhost:1313/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ Tue, 01 Sep 2015 21:05:00 +0000 - - https://rnemeth90.github.io/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ - <p>This script will iterate through all computers in Active Directory and return the configured time server for each computer.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span><span style="color:#75715e">&lt;# -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">SYNOPSIS</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Get time source for all computers in domain -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">EXAMPLE</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Get-TimeSource -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">NOTES</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Author: Ryan Nemeth - RyanNemeth@live.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Site: http://www.geekyryan.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">LINK</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> http://www.geekyryan.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">DESCRIPTION</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> This function will iterate through all computers/servers in a domain and return the time source -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> for each. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#&gt;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Write-Host -foregroundcolor Red -BackgroundColor black <span style="color:#e6db74">&#34;This script must be run on a domain controller and requires that the AD Powershell module be installed&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$module = Get-Module -ListAvailable | Select-Object -ExpandProperty Name -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span>($module <span style="color:#f92672">-notcontains</span> <span style="color:#e6db74">&#34;ActiveDirectory&#34;</span>) { -</span></span><span style="display:flex;"><span> Write-Host -foregroundcolor red -backgroundcolor black <span style="color:#e6db74">&#34;***Active Directory Powershell Module Not Found***&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span> { -</span></span><span style="display:flex;"><span> Write-Host -foregroundcolor yellow <span style="color:#e6db74">&#34;Found Active Directory Powershell Module. Importing...&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Import-Module ActiveDirectory -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$computers = get-adcomputer -filter * | Select-Object -ExpandProperty Name -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span>($computer <span style="color:#66d9ef">in</span> $computers) { -</span></span><span style="display:flex;"><span> $tm_source = w32tm /query /computer<span style="color:#960050;background-color:#1e0010">:</span>$computer /source -</span></span><span style="display:flex;"><span> write-host <span style="color:#e6db74">&#34;The time source for&#34;</span> $computer <span style="color:#e6db74">&#34;is&#34;</span> $tm_source -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><img src="https://github.com/rnemeth90/PowerShell/blob/master/NTP/Get-TimeSource.ps1" alt=""></p> - - - + http://localhost:1313/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ + This script will iterate through all computers in Active Directory and return the configured time server for each computer. &lt;# .SYNOPSIS Get time source for all computers in domain .EXAMPLE Get-TimeSource .NOTES Author: Ryan Nemeth - RyanNemeth@live.com Site: http://www.geekyryan.com .LINK http://www.geekyryan.com .DESCRIPTION This function will iterate through all computers/servers in a domain and return the time source for each. #&gt; Write-Host -foregroundcolor Red -BackgroundColor black &#34;This script must be run on a domain controller and requires that the AD Powershell module be installed&#34; $module = Get-Module -ListAvailable | Select-Object -ExpandProperty Name if($module -notcontains &#34;ActiveDirectory&#34;) { Write-Host -foregroundcolor red -backgroundcolor black &#34;***Active Directory Powershell Module Not Found***&#34; } else { Write-Host -foregroundcolor yellow &#34;Found Active Directory Powershell Module. + Error When Reinstalling DirSync - https://rnemeth90.github.io/posts/2015-08-13-error-when-reinstalling-dirsync/ + http://localhost:1313/posts/2015-08-13-error-when-reinstalling-dirsync/ Thu, 13 Aug 2015 18:59:00 +0000 - - https://rnemeth90.github.io/posts/2015-08-13-error-when-reinstalling-dirsync/ - <p>Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process:</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2015/08/1.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/1.png" alt=""></a></p> -<p>I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do:</p> -<ul> -<li>Uninstall Windows Azure Active Directory Sync tool and reboot -<a href="https://geekyryan.com/wp-content/uploads/2015/08/2.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/2.png" alt=""></a></li> -</ul> -<p>Remove this directory and all subfolders: C:Program FilesWindows Azure Active Directory Sync -<a href="https://geekyryan.com/wp-content/uploads/2015/08/3.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/3.png" alt=""></a></p> -<p>If you created a domain account to use for DirSync, remove it. Also remove the Office 365 account you created.</p> -<ul> -<li>Delete the Group accounts that the DirSync wizard created. Their names all begin with “FIM”</li> -</ul> -<p><a href="https://geekyryan.com/wp-content/uploads/2015/08/4.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/4.png" alt=""></a></p> -<p>Uninstall MSSQL:</p> -<ul> -<li>Delete the MSSQL directory: C:Program FilesMicrosoft SQL Server</li> -<li>Reboot!</li> -<li>You should be able to install and configure DirSync now.</li> -</ul> -<p><a href="https://geekyryan.com/wp-content/uploads/2015/08/5.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/5.png" alt=""></a></p> - - - + http://localhost:1313/posts/2015-08-13-error-when-reinstalling-dirsync/ + Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process: I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do: + Failed to Mount Exchange 2010 Database - https://rnemeth90.github.io/posts/2015-08-12-failed-to-mount-exchange-2010-database/ + http://localhost:1313/posts/2015-08-12-failed-to-mount-exchange-2010-database/ Wed, 12 Aug 2015 12:59:00 +0000 - - https://rnemeth90.github.io/posts/2015-08-12-failed-to-mount-exchange-2010-database/ - <p>Recently, one of my users’ came to me and said he was missing two months worth of email. This was just after migrating to Exchange Online. We were using Exchange 2010 with System Center DPM for backups.</p> -<p>I restored the database that the users’ mailbox was on from a backup then copied it over to the Exchange server from the network share I restored it to. All was going well, until I tried to mount the darn thing.</p> -<p>I was getting this error and could not for the life of me decry-pt the meaning of it. There is obviously some type of IO issue/file not found. But what could it be?</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/1-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/1-1.png" alt=""></a></p> -<p>I figured I’d better kick this one off with some basic troubleshooting. First, I checked the health of the database and made sure it was clean. Passed that test…</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/2-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/2-1.png" alt=""></a></p> -<p>Then ran a repair on the database, to no avail.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/3-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/3-1.png" alt=""></a></p> -<p>After racking my brain for a good thirty minutes, and a few failed Google searches, I found the solution. It was so simple! I created the log file directory in the folder with the database, and voila, the database mounted without a single error!</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/7.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/7.png" alt=""></a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/4-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/4-1.png" alt=""></a><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/5-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/5-1.png" alt=""></a></p> -<p>I was able to see the ‘supposed’ location of the log file by opening the Exchange Management Shell and running the ‘Get-MailboxDatabase’ cmdlet, like so:</p> -<p><em>Get-MailBoxDatabase –Identity <Recovery DB Name> | FL Name, ServerName, EDBFilePath, LogFolderPath</em></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/6.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/6.png" alt=""></a></p> -<p>I’m not sure why the database mounting process isn’t capable of creating the log file directory… I think Microsoft would have thought and planned for a situation like this. Hope this helps!</p> - - - + http://localhost:1313/posts/2015-08-12-failed-to-mount-exchange-2010-database/ + Recently, one of my users’ came to me and said he was missing two months worth of email. This was just after migrating to Exchange Online. We were using Exchange 2010 with System Center DPM for backups. I restored the database that the users’ mailbox was on from a backup then copied it over to the Exchange server from the network share I restored it to. All was going well, until I tried to mount the darn thing. + Ping Sweeping with FPing - https://rnemeth90.github.io/posts/2015-03-09-ping-sweeping-with-fping/ + http://localhost:1313/posts/2015-03-09-ping-sweeping-with-fping/ Mon, 09 Mar 2015 01:08:00 +0000 - - https://rnemeth90.github.io/posts/2015-03-09-ping-sweeping-with-fping/ - <p>I generally use NMAP for any type of host discovery, but recently started experimenting with FPing. One thing I found is that, when performing a ping sweep, not only do I see the hosts that replied to the ping, but FPing also sends any unreachable IP addresses to stdout (which is super annoying and ugly if you ask me…).</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h04_50.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h04_50.png" alt=""></a></p> -<p>Anyway, after a bit of research, I found a nifty way to suppress these messages. Linux allows us to redirect all error messages to /dev/null. So instead of just running the vanilla fping -a -g…. you would run the program and output all error messages /dev/null, like so:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h07_14.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h07_14.png" alt=""></a></p> - + http://localhost:1313/posts/2015-03-09-ping-sweeping-with-fping/ + I generally use NMAP for any type of host discovery, but recently started experimenting with FPing. One thing I found is that, when performing a ping sweep, not only do I see the hosts that replied to the ping, but FPing also sends any unreachable IP addresses to stdout (which is super annoying and ugly if you ask me…). Anyway, after a bit of research, I found a nifty way to suppress these messages. - Powershell: SID to Username - https://rnemeth90.github.io/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ + http://localhost:1313/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ Mon, 08 Dec 2014 13:43:00 +0000 - - https://rnemeth90.github.io/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ - <p>This is a simple script to convert a SID to a username</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span><span style="color:#75715e"># Returns a username based on a SID</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Author: Ryan Nemeth</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Date: 12/2/2014</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$SID = read-host <span style="color:#960050;background-color:#1e0010">“</span>Please enter the SID<span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#960050;background-color:#1e0010">”</span> -</span></span><span style="display:flex;"><span>$object = New-Object System.Security.Principal.SecurityIdentifier($SID) -</span></span><span style="display:flex;"><span>$User = $object.Translate( \[System.Security.Principal.NTAccount\]) -</span></span><span style="display:flex;"><span>write-host <span style="color:#960050;background-color:#1e0010">“</span>The user is<span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#960050;background-color:#1e0010">”</span> $User.Value -</span></span></code></pre></div> - - + http://localhost:1313/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ + This is a simple script to convert a SID to a username # Returns a username based on a SID # Author: Ryan Nemeth # Date: 12/2/2014 $SID = read-host “Please enter the SID: ” $object = New-Object System.Security.Principal.SecurityIdentifier($SID) $User = $object.Translate( \[System.Security.Principal.NTAccount\]) write-host “The user is: ” $User.Value + DHCP Address Negotiation Process - https://rnemeth90.github.io/posts/2014-12-08-dhcp-address-negotiation-process/ + http://localhost:1313/posts/2014-12-08-dhcp-address-negotiation-process/ Mon, 08 Dec 2014 03:08:00 +0000 - - https://rnemeth90.github.io/posts/2014-12-08-dhcp-address-negotiation-process/ - <p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/12/2014-12-07_22h07_33.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/12/2014-12-07_22h07_33.png" alt=""></a></p> - + http://localhost:1313/posts/2014-12-08-dhcp-address-negotiation-process/ + - Unlock a Domain User from CMD Line - https://rnemeth90.github.io/posts/2014-12-08-unlock-domain-user-from-cmd-line/ + http://localhost:1313/posts/2014-12-08-unlock-domain-user-from-cmd-line/ Mon, 08 Dec 2014 02:11:00 +0000 - - https://rnemeth90.github.io/posts/2014-12-08-unlock-domain-user-from-cmd-line/ - <p>To unlock a domain user from the command line, use this command:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>net user &amp;lt;username&amp;gt; /domain /active:yes -</span></span></code></pre></div><p>This can also be done using Powershell:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Unlock-ADAccount -identity <span style="color:#960050;background-color:#1e0010">“</span>CN=John,OU=myUsers,DC=myDomain,DC=local<span style="color:#960050;background-color:#1e0010">”</span> -</span></span></code></pre></div> + http://localhost:1313/posts/2014-12-08-unlock-domain-user-from-cmd-line/ + To unlock a domain user from the command line, use this command: net user &amp;lt;username&amp;gt; /domain /active:yes This can also be done using Powershell: Unlock-ADAccount -identity “CN=John,OU=myUsers,DC=myDomain,DC=local” - The Case of Transitive Trusts and Dropped RPC Connections - https://rnemeth90.github.io/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ + http://localhost:1313/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ Tue, 25 Nov 2014 01:27:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ - <p>I was at a client earlier this morning, working to get a transitive forest trust setup between their two domains. Setting up the trust on ServerA to DomainB went without issue. However, when trying to create the trust between ServerB and DomainA, I received this error: The secure channel reset on Active Directory Domain Controller (Your domain controller) of domain (Your domain) to domain (your other domain) failed with error: RPC server is unavailable.</p> -<p>Troubleshooting (as always) started off with the basics: is the firewall on or off, are the services running, are the names being properly resolved, etc. Well, the Windows Firewall on both servers was off and -the RPC services were running. So what now?? I fired up NMAP on ServerB and did a syn scan on ServerA. After reviewing the output, I could see that the ports were open. I then went over to ServerA and opened up the Services MSC console. The RPC services appeared to be running. Being that they are system services and you cannot manually interact with them, I was unable to manually restart them. Just out of curiosity,</p> -<p>I opened a command prompt while connected to that server and ran Netstat -A. This is when I had the “AHA!” moment. Nothing was listening on any of the RPC ports! I rebooted the server (something I don’t really like to do..), logged in and ran Netstat -A again. This time, RPC was listening. I went back over to ServerB, walked through the New Trust Wizard, and success! Oh, the feeling of victory!</p> - + http://localhost:1313/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ + I was at a client earlier this morning, working to get a transitive forest trust setup between their two domains. Setting up the trust on ServerA to DomainB went without issue. However, when trying to create the trust between ServerB and DomainA, I received this error: The secure channel reset on Active Directory Domain Controller (Your domain controller) of domain (Your domain) to domain (your other domain) failed with error: RPC server is unavailable. - Creating Applocker Policies - https://rnemeth90.github.io/posts/2014-11-17-creating-applocker-policies/ + http://localhost:1313/posts/2014-11-17-creating-applocker-policies/ Mon, 17 Nov 2014 01:40:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-17-creating-applocker-policies/ - <p>Application Control Policies can be used to restrict what programs a user is allowed to run. They can be created at the local Group Policy level or the Domain GPO level. There are 4 different types of Applocker RULES that you can implement, depending on what type of executable you want to control access to.</p> -<p>Executable Rules – EXE’s, COM’s, etc.</p> -<p>Script Rules – batch files, VB scripts, etc.</p> -<p>AppX Rules – AppX Packages (Windows 8.1/Server 2012 R2 Metro Interface programs)</p> -<p>Windows Installer Rules – Windows Installer Packages and MSU Packages</p> -<p>After choosing what type of executable file you want to control, you can choose the corresponding rule type. Then, you will be able to choose the criteria for that rule type. Applocker rule criteria are things such as file path, publisher, and file hash. Criteria allow you to be more granular with your selections. Rather than saying you want to block access to ALL executable’s on a computer, you can choose to block access to executable’s published by a certain vendor, or found in a specified directory.</p> -<p>Applocker can be found in the Group Policy Editor at: Computer Configuration\Windows Settings\Security Settings. Application Control Policies. By right-clicking on the Applocker node, you can configure rule enforcement. You have the option to enforce rules or audit rules based on rule type. Auditing will allow</p> -<p>you get a good grasp on what Applocker will do in your environment if you are unsure.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h18_31.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h18_31.png" alt=""></a></p> -<p>Clicking the Advanced tab of this window will allow you to configure rule enforcement for Dynamic Link Libraries. It’s best to leave DLL rule enforcement disabled, because it can cause a system to suffer dramatic performance hits.</p> -<p>Underneath the Applocker node, you will find nodes for the 4 different rule types. You can create new rules by right clicking on any of these nodes and clicking “Create New Rule”. Before creating any rules, I advise you to create the default rules. Doing this will ensure that users are still able to run programs in the Program Files directory and the Windows directory. Also, members of the built-in Administrators group will be allowed to run ANY files.</p> -<p>When creating custom Applocker rules, you can choose to allow or deny the program, and what group the rule will apply to (by default, the “Everyone” special identity is always selected).</p> -<p>You will also be able to choose the criteria for the executable that you are controlling.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h26_30.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h26_30.png" alt=""></a></p> -<p>If the executable has a digital signature from the software publisher, choose “Publisher”. Doing so will give you even more options:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h28_47.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h28_47.png" alt=""></a></p> -<p>This allows you to really drill down and get granular with the rule. Microsoft allows us to control access to the file based on the Publisher, the Product Name, the File Name, and even the File Version.</p> -<p>Creating rules based on File Path criteria is not advised, being that if the file jumps directories, the rule will no longer apply. I also don’t advise using the File Hash criteria. My reason behind this is, if the file gets updated, the hash changes. If that happens, the rule is no longer valid.</p> -<p>After choosing the criteria type you would like to use, you can choose to create exceptions, if any. When multiple rules conflict, the order of precedence is Publisher, File Hash, and then File Path. So Publisher rules will always override File Hash rules, File Hash rules will always override File Path rules, and you get the point…</p> -<p>Finally, in order for your endpoint workstations to process Applocker rules, the Application Identity Service must be running. I like to control this with the same GPO that I configure Applocker in.</p> - - - + http://localhost:1313/posts/2014-11-17-creating-applocker-policies/ + Application Control Policies can be used to restrict what programs a user is allowed to run. They can be created at the local Group Policy level or the Domain GPO level. There are 4 different types of Applocker RULES that you can implement, depending on what type of executable you want to control access to. Executable Rules – EXE’s, COM’s, etc. Script Rules – batch files, VB scripts, etc. AppX Rules – AppX Packages (Windows 8. + TCP/IP Network Fundamentals - https://rnemeth90.github.io/posts/2014-11-16-tcpip-network-fundamentals/ + http://localhost:1313/posts/2014-11-16-tcpip-network-fundamentals/ Sun, 16 Nov 2014 21:20:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-16-tcpip-network-fundamentals/ - <p>Going over the basics of network fundamentals and all the models and ideas behind them. The most pushed idea is the OSI networking model which consists of 7 layers, all of which deal with a certain aspect of the networking model.</p> -<p>A P S T N D P</p> -<p>From the top down this represents the following</p> -<p>Layer 7: Application – This layer is the channel between software and external requests. For example, a web server would work with this layer to process HTTP requests.</p> -<p>Layer 6: Presentation – This layer organizes data formats such as JPEG, Text, ASCII, etc</p> -<p>Layer 5: Session – This layer deals with session control; How a conversation should start, function, and end. It can be considered the broken between the layer below and the layers above. It will ensure all the data is proper when being passed up or down.</p> -<p>Layer 4: Transport – This layer is solely focused on data delivery. It deals with many protocols, but most notably it deals with TCP and UDP packets, any checksum errors, and error recovery</p> -<p>Layer 3: Network – This layer deals with logical addressing and routing. It deals with the actual delivery of packets across multiple networks.</p> -<p>Layer 2: Data Link – This layer deals with the rules of how data can be transmitted over a wire such as CSMA/CD and the like. It also deals with encapsulating frames to be transported over a local network</p> -<p>Layer 1: Physical – The actual hardware and electrical signaling to move data over the network. Network cards, cabling, and other hardware are part of this layer</p> -<p>Generic overview of the OSI model above lets work on the idea of some older and modern networks.</p> -<p>Hubs – Devices that simply take a signal and regenerate it out of all ports that are connected.</p> -<p>Switches – Devices that take a signal and make some sort of smart decision to provide a single path from one port to another</p> -<p>Routers – Devices that make decisions based upon higher level information (logical addressing) and will make intelligent decisions on how to handle that data, both incoming and outgoing. Segments networks into two different ones.</p> -<p>Bridge – A device that segments a network in two.</p> -<p>Collision Domain – The bounds where a collision may occur. This is relevant for networks utilizing half-duplex communication and for older devices such as hubs.</p> -<p>Broadcast Domain – The bounds where a broadcast can reach.</p> -<p>Collision Domains: Forgive the visio art, it will get better… hopefully</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h18_36.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h18_36.png" alt=""></a></p> -<p><a href="http://xenodez.pleasedonthack.us/?attachment_id=49">&lt;span style=&ldquo;color: windowtext; font-family: &ldquo;Verdana&rdquo;,sans-serif; font-size: 9.0pt; mso-no-proof: yes; text-decoration: none; text-underline: none;&quot;&gt;</a></p> -<p>Every computer connected to that hub is in the collision domain noted by the circle. With a hub, the signal gets sent to every device connected to it, regardless of whether it was meant to go to that machine or not. When the PC at the top left sends information at the same time as the PC on the bottom right, a collision is likely to occur</p> -<p><a href="http://xenodez.pleasedonthack.us/?attachment_id=52">&lt;span style=&ldquo;color: windowtext; font-family: &ldquo;Verdana&rdquo;,sans-serif; font-size: 9.0pt; mso-no-proof: yes; text-decoration: none; text-underline: none;&quot;&gt;</a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h18_45.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h18_45.png" alt=""></a></p> -<p>Every computer connected to this switch is limited in its collision domain to the port on the switch and the network card in the PC. The reason being that switches do not just take a signal and send it out of all the ports, it is intelligent enough to be able to send information directly to the PC it needs to. This is further mitigated by the fact that a computer connected to a switch may operate at full-duplex, allowing both simultaneous sending and receiving of information.</p> -<p>Collisions and how they are handled:</p> -<p>The way computers avoid collision in this sense is via something called CSMA/CD or Carrier Sense Multiple Access/Collision Avoidance. The way it works is this, a computer will wait until the line is silent before sending information. Every computer will listen to determine whether the line is truly clear. If two computers were to send at the same time, and a collision were to occur, the computers will immediately trigger a random back off time in which they will not try resending that information until the timer is up.</p> -<p>Unicast vs Broadcast vs Multicast</p> -<p>The idea between these concepts is fairly simple. Unicast deals with a transmission that is intended for one recipient. A broadcast is a transmission that is meant for all recipients that are able to hear it. Multicast is intended for a specific group of recipients.</p> - - - + http://localhost:1313/posts/2014-11-16-tcpip-network-fundamentals/ + Going over the basics of network fundamentals and all the models and ideas behind them. The most pushed idea is the OSI networking model which consists of 7 layers, all of which deal with a certain aspect of the networking model. A P S T N D P From the top down this represents the following Layer 7: Application – This layer is the channel between software and external requests. For example, a web server would work with this layer to process HTTP requests. + BranchCache - https://rnemeth90.github.io/posts/2014-11-16-branchcache/ + http://localhost:1313/posts/2014-11-16-branchcache/ Sun, 16 Nov 2014 21:16:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-16-branchcache/ - <p>Branchcache is a technology unique to Windows 7 and Windows Server 2008 R2. It provides faster connection to shared files across wide area networks. Branchcache works by caching content hosted on remote servers on a local caching server in the LAN. When a client queries for data on a remote server, it first looks in the local caching server. If the data is not found there, the remote server is accessed and transfer’s the data to the local caching server, where it is then accessed by the client who originally made the request. That way, all future client requests will not have to go across the wide area network, rather opting to access the local caching server until the data changes.</p> -<p>Branchcache is only available on Windows 7 clients running Enterprise or Ultimate, and Windows Server 2008 R2. Branchcache becomes active when the round trip latency time from client to remote server exceeds 80 milliseconds.</p> -<p>Branchcache is available in two modes: distributed cache mode and hosted cache mode. What you just read above was the basics of hosted cached mode. Distributed cache mode works differently to achieve the same results. When a client accesses data across the WAN, it stores that data in its own cache. This way, if another client needs access to the data, it can retrieve it locally. Also, this allows each client to host part of the cache, rather than one machine hosting the entire cache.</p> -<p>There are two steps to configuring Branchcache on a Windows 7 client. I will not include the server configuration at this point in time.</p> -<p>Enable Branchcache (Hosted or Distributed, Server 08 R2 will be required for Hosted mode)</p> -<p>Configure the appropriate ports within the Windows Firewall</p> -<p>You can enable Branchcache from within Group Policy or by using the Netsh command. When using Group Policy, navigate to Computer Configuration &gt; Administrative Templates &gt; Network &gt; Branchcache. From here you can turn on Branchcache and enable the mode you want to use. You can also set the percentage of disk space to be used for caching. After this, open the Windows Firewall and unblock the Branchcache ports. You only need to do this when configuring Branchcache via Group Policy. Using the Netsh command automatically configures the firewall. Here are the basic commands for Netsh:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>Netsh Branchcache set service mode<span style="color:#f92672">=</span>distributed -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Netsh Branchcache reset -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Netsh Branchcache show status -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Netsh Branchcache set cachesize -</span></span></code></pre></div><p>*Configuring Branchcache must be done from an administrative command prompt.</p> - - - + http://localhost:1313/posts/2014-11-16-branchcache/ + Branchcache is a technology unique to Windows 7 and Windows Server 2008 R2. It provides faster connection to shared files across wide area networks. Branchcache works by caching content hosted on remote servers on a local caching server in the LAN. When a client queries for data on a remote server, it first looks in the local caching server. If the data is not found there, the remote server is accessed and transfer’s the data to the local caching server, where it is then accessed by the client who originally made the request. + File History - https://rnemeth90.github.io/posts/2014-11-15-file-history/ + http://localhost:1313/posts/2014-11-15-file-history/ Sat, 15 Nov 2014 20:02:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-15-file-history/ - <p>File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. To begin using it, connect an external drive and search for File History on the Start Screen:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-15_14h19_47.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-15_14h19_47.png" alt=""></a></p> -<p>After opening File History, you will see this screen:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-15_14h20_32.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-15_14h20_32.png" alt=""></a></p> -<p>To enable File History, click the ‘Turn On’ button. You can select the drive you want to use by clicking ‘Select Drive’ on the left hand side from this same screen. The first time you enable File History, it will create a full backup of all files on your computer, except for files that you do not access (system files), and files you have chosen to exclude. From then on, it will create a versioned copy of every file that has changed since the last backup.</p> -<p>You can use a locally attached drive or a network share for File History. To choose how often File History backs up files; choose ‘Advanced Settings’. From here you can also choose how much space on the drive is used, and how long saved versions of files should be kept.</p> -<p>When the total space allocated to File History has been used, the feature will delete the oldest versions of files to make room for newer versions.</p> - - - + http://localhost:1313/posts/2014-11-15-file-history/ + File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. + Layer 2 Switching Fundamentals - https://rnemeth90.github.io/posts/2012-11-16-layer-2-switching-fundamentals/ + http://localhost:1313/posts/2012-11-16-layer-2-switching-fundamentals/ Fri, 16 Nov 2012 21:26:00 +0000 - - https://rnemeth90.github.io/posts/2012-11-16-layer-2-switching-fundamentals/ - <p>Switches are devices that support a large number of ports to connect devices to the network.</p> -<h3 id="design" >Design: -<span> - <a href="#design"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h3><p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h22_54.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h22_54.png" alt=""></a></p> -<p>More towards a CCNP or CCDA topic, but designing a network when it comes to the switching side can be done in three building blocks. The access layer, the distribution layer, and the core layer. The access layer generally has a high port density, can support VLANs, QoS, and access lists. The distribution layer will aggregate multiple access layer switches. These are also generally Layer 3 switches to allow routing among an enterprise. It will need to be able to handle the volume of traffic in addition to supporting the same features as the access layer switches. The core layer is the device which will need the highest bandwidth backplane to deal with all of the traffic.</p> -<h3 id="how-switches-handle-traffic" >How switches handle traffic: -<span> - <a href="#how-switches-handle-traffic"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h3><p>A switch is an intelligent device that can make some decisions on how to handle the data it is given. Switches can be divided into two categories for these decisions: Layer 2 or Layer 3 switches. For the CCNA we will only be interested in the layer 2 switches. Layer 2 switches operate at the data link layer. This layer deals primarily with MAC addresses. A Layer 2 switch will build a CAM table full of dynamically learned MAC addresses. The way it learns these addresses is by inspecting the layer 2 header/trailer and learning the source MAC addresses on the frames it receives. A frame is what a packet is encapsulated in when it moves from device to device across the network.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h23_04.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h23_04.png" alt=""></a></p> -<p>With this example the switch has learned PC1/PC2/and PC3′s MAC addresses. If a packet came in on Fa0/4 from PC4, the switch would look at the source MAC address and put an entry for 4444.4444.4444 on Fa0/4. A switch will route traffic based on this table. There are a few decisions it must make to determine how to handle traffic. When it first receives a frame it will consult it’s CAM table to determine whether or not it has the source MAC address listed for that port. If not, it will add it to the CAM table. In the example above, PC1 sent a frame to the switch, the switch noticed PC1′s MAC address was not in it’s table and added it. The next thing it looks at is the destination MAC address. The CAM table is again consulted. If it finds a match the switch will send the frame directly to the recipient it needs to on whatever port it is on. In the example above, PC1 sends a frame to PC3. Because the switch sees 1111.1111.1111 sending to 3333.3333.3333 and has an entry for 3333.3333.3333 it will send the frame out of port Fa0/3 to the recipient. If a destination is not in the CAM table the switch will need to try to find the recipient. In this case the switch will decide to broadcast the frame out of every port EXCEPT the one it came in on. In this example, PC1 sends a frame destined for PC4. The switch will see a frame from 1111.1111.1111 to 4444.4444.4444. PC4′s MAC address is not in it’s table. The switch will then send the frame out of every port except for Fa0/1 (the source). When PC2 and PC3 get this frame, it will determine if the frame was meant for it, and if not it will ignore it. PC4 will also make the same decision and PC4 will respond. Once PC4 has responded the switch will be able to add PC4′s MAC address to it’s table on Fa0/4.</p> - - - + http://localhost:1313/posts/2012-11-16-layer-2-switching-fundamentals/ + Switches are devices that support a large number of ports to connect devices to the network. Design: Link to heading More towards a CCNP or CCDA topic, but designing a network when it comes to the switching side can be done in three building blocks. The access layer, the distribution layer, and the core layer. The access layer generally has a high port density, can support VLANs, QoS, and access lists. + User Account Control - https://rnemeth90.github.io/posts/2012-11-15-user-account-control-copy/ + http://localhost:1313/posts/2012-11-15-user-account-control-copy/ Thu, 15 Nov 2012 16:01:00 +0000 - - https://rnemeth90.github.io/posts/2012-11-15-user-account-control-copy/ - <p>Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system.</p> -<p>For a standard user, a token with the most basic privileges is assigned. Administrators have two tokens assigned, the first token contains all privileges usually awarded to an administrator (unrestricted), and the second is similar to that awarded to a basic user. This way, all programs that the administrator runs, including the Windows Shell, are run in basic user mode (this is why administrators still receive UAC prompts, but do not get asked for credentials). When an application requests higher privileges, the higher integrity token is used .</p> -<p>User Account Control prompts each have their own meaning based on the color (blue, grey, yellow, or red. The blue prompt (Figure 1) means that a built in Windows component that is signed by Microsoft is requesting administrative privileges to continue. This prompt has a multicolored shield in the upper left corner. The grey prompt (Figure 2) means a software application that is signed by a third party developer is requesting admin privileges. This prompt has a yellow shield with a black exclamation mark in the upper left corner. The yellow prompt (Figure 3) signifies that a unsigned executable is requesting administrator privileges. This prompt also had a yellow shield with black exclamation mark in the upper left corner, and looks somewhat generic. Finally, the red prompt (Figure 4) means a program that was specifically blocked by an administrator has attempted to run.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BBlue.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BBlue.png" alt=""></a></p> -<p>Figure 1</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BGrey.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BGrey.png" alt=""></a></p> -<p>Figure 2</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BYellow.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BYellow.png" alt=""></a></p> -<p>Figure 3</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BRED.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BRED.png" alt=""></a></p> -<p>Figure 4</p> - - - + http://localhost:1313/posts/2012-11-15-user-account-control-copy/ + Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system. + User Account Control - https://rnemeth90.github.io/posts/2012-11-15-user-account-control/ + http://localhost:1313/posts/2012-11-15-user-account-control/ Thu, 15 Nov 2012 16:01:00 +0000 - - https://rnemeth90.github.io/posts/2012-11-15-user-account-control/ - <p>Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system.</p> -<p>For a standard user, a token with the most basic privileges is assigned. Administrators have two tokens assigned, the first token contains all privileges usually awarded to an administrator (unrestricted), and the second is similar to that awarded to a basic user. This way, all programs that the administrator runs, including the Windows Shell, are run in basic user mode (this is why administrators still receive UAC prompts, but do not get asked for credentials). When an application requests higher privileges, the higher integrity token is used.</p> -<p>User Account Control prompts each have their own meaning based on the color (blue, grey, yellow, or red. The blue prompt (Figure 1) means that a built in Windows component that is signed by Microsoft is requesting administrative privileges to continue. This prompt has a multicolored shield in the upper left corner. The grey prompt (Figure 2) means a software application that is signed by a third party developer is requesting admin privileges. This prompt has a yellow shield with a black exclamation mark in the upper left corner. The yellow prompt (Figure 3) signifies that a unsigned executable is requesting administrator privileges. This prompt also had a yellow shield with black exclamation mark in the upper left corner, and looks somewhat generic. Finally, the red prompt (Figure 4) means a program that was specifically blocked by an administrator has attempted to run.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BBlue.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BBlue.png" alt=""></a></p> -<p>Figure 1</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BGrey.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BGrey.png" alt=""></a></p> -<p>Figure 2</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BYellow.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BYellow.png" alt=""></a></p> -<p>Figure 3</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BRED.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BRED.png" alt=""></a></p> -<p>Figure 4</p> - - - + http://localhost:1313/posts/2012-11-15-user-account-control/ + Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system. + About - https://rnemeth90.github.io/about/ + http://localhost:1313/about/ Mon, 01 Jan 0001 00:00:00 +0000 - - https://rnemeth90.github.io/about/ - <img src="https://geekyryan.com/wp-content/uploads/2022/01/image.png" alt="drawing" width="200"/> -<p>My name is Ryan Nemeth and this is my personal blog. I write down my thoughts regarding Microsoft Azure, Kubernetes, cloud-native technologies, and software development. I find that documenting these things not only helps others but also helps reinforce my own knowledge as well. I may also blog about life or other random things from time to time.</p> -<p>This blog has had many lives over the years. It originally started as a Blogger blog way back in 2012, moved to Wordpress for a while, then back to blogger, then to Ghost (running on a small droplet over @ DigitalOcean), then back to Wordpress again, and now here on Github pages. That&rsquo;s a lot of change (such is life)! So if you happen to come across a page that has some weird formatting, missing images, etc. Please be kind and let me know so that I may fix it.</p> -<p>I&rsquo;m currently working remote as a Senior DevOps Engineer/SRE for Aprimo on the Systems team.</p> -<p>Before joining Aprimo, I was a cloud architect for a software company specializing in HCM software.</p> -<p>The opinions expressed here are my own personal opinions, and do not represent my employer’s view in any way.</p> -<p>Contact me through <a href="https://www.linkedin.com/in/ryan-nemeth-b0b1504b/">LinkedIn</a> or <a href="https://github.com/rnemeth90">Github</a>. -<br> -<br></p> -<h2 id="currently-reading" >Currently Reading: -<span> - <a href="#currently-reading"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><ul> -<li><input disabled="" type="checkbox"> <a href="https://www.amazon.com/How-Linux-Works-Brian-Ward/dp/1718500408/ref=sr_1_1?crid=1VMED792IBVXJ&amp;keywords=how+linux+works&amp;qid=1672841276&amp;s=books&amp;sprefix=how+linux+work%2Cstripbooks%2C92&amp;sr=1-1">How Linux Works</a></li> -<li><input disabled="" type="checkbox"> <a href="https://www.amazon.com/Learning-Go-Idiomatic-Real-World-Programming/dp/1492077216/ref=sr_1_1?crid=YF687N53959K&amp;keywords=learning+go&amp;qid=1659346533&amp;sprefix=learning+go%2Caps%2C102&amp;sr=8-1">Learning Go</a></li> -<li><input disabled="" type="checkbox"> <a href="https://www.amazon.com/Learning-Go-Idiomatic-Real-World-Programming/dp/1492077216/ref=sr_1_1?crid=YF687N53959K&amp;keywords=learning+go&amp;qid=1659346533&amp;sprefix=learning+go%2Caps%2C102&amp;sr=8-1">Powerful Command-Line Applications in Go</a></li> -</ul> -<h2 id="finished" >Finished -<span> - <a href="#finished"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><ul> -<li><input checked="" disabled="" type="checkbox"> <a href="https://www.amazon.com/Microservices-Second-Christian-Horsdal-Gammelgaard/dp/1617297925/ref=sr_1_2_sspa?crid=QPYAG2EFADPZ&amp;keywords=microservices+in+.net&amp;qid=1659346935&amp;s=digital-text&amp;sprefix=microservices+in+.ne%2Cdigital-text%2C73&amp;sr=1-2-spons&amp;psc=1&amp;spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUEzTFFTTVdJNjA0V1FCJmVuY3J5cHRlZElkPUEwNDU1MTc3MlE1VENVUEdQSVVCVSZlbmNyeXB0ZWRBZElkPUEwOTk5NzAwU0lOUUlWMzBEVTNNJndpZGdldE5hbWU9c3BfYXRmJmFjdGlvbj1jbGlja1JlZGlyZWN0JmRvTm90TG9nQ2xpY2s9dHJ1ZQ==">Microservices in .NET</a></li> -<li><input checked="" disabled="" type="checkbox"> <a href="https://www.amazon.com/Kubernetes-Patterns-Designing-Cloud-Native-Applications-ebook/dp/B07QH3JCC6/ref=sr_1_1?keywords=kubernetes+patterns&amp;qid=1659346980&amp;s=digital-text&amp;sprefix=kubernetes+patt%2Cdigital-text%2C83&amp;sr=1-1">Kubernetes Patterns</a></li> -<li><input checked="" disabled="" type="checkbox"> <a href="https://www.amazon.com/10-NET-Cross-Platform-Development-websites/dp/1801077363/ref=sr_1_1?keywords=c%23+10+and+.net+6&amp;qid=1659346562&amp;sprefix=c%23+10+and+.net+%2Caps%2C81&amp;sr=8-1">C# 10 and .NET 6</a></li> -<li><input checked="" disabled="" type="checkbox"> <a href="https://www.amazon.com/C-Players-Guide-5th/dp/0985580151/ref=sr_1_1?crid=1UMSSS98U2DA4&amp;keywords=c%23+players+guide&amp;qid=1659346365&amp;sprefix=c+players+guid%2Caps%2C80&amp;sr=8-1">C# Players Guide</a></li> -<li><input checked="" disabled="" type="checkbox"> <a href="https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship-ebook/dp/B001GSTOAM/ref=sr_1_1?crid=10U2VHYBRS2FA&amp;keywords=clean+code&amp;qid=1659347015&amp;s=digital-text&amp;sprefix=clean+cod%2Cdigital-text%2C88&amp;sr=1-1">Clean Code</a></li> -<li><input checked="" disabled="" type="checkbox"> <a href="https://www.amazon.com/Site-Reliability-Engineering-Production-Systems-ebook/dp/B01DCPXKZ6/ref=sr_1_1?keywords=site+reliability+engineering&amp;qid=1659346602&amp;sprefix=site+reli%2Caps%2C79&amp;sr=8-1">Site Reliability Engineering</a></li> -<li><input checked="" disabled="" type="checkbox"> <a href="https://www.amazon.com/Hands-Azure-Developers-ecosystems-containers/dp/1789340624/ref=sr_1_1?keywords=hands-on+azure+for+developers&amp;qid=1659346632&amp;sprefix=hands+on+azure+for+deve%2Caps%2C83&amp;sr=8-1">Hands-On Azure for Developers</a></li> -<li><input checked="" disabled="" type="checkbox"> <a href="https://www.amazon.com/Kubernetes-Running-Dive-Future-Infrastructure-ebook/dp/B07YP1XSZ9/ref=sr_1_1?keywords=kubernetes+up+and+running&amp;qid=1659346866&amp;s=digital-text&amp;sprefix=kubernetes+up+and%2Cdigital-text%2C75&amp;sr=1-1">Kubernetes Up and Running</a></li> -<li><input checked="" disabled="" type="checkbox"> <a href="https://www.amazon.com/Kubernetes-Best-Practices-Blueprints-Applications-ebook/dp/B081J62KLW/ref=sr_1_1?crid=1OLDKB8KZ2G7N&amp;keywords=kubernetes+best+practices&amp;qid=1659346894&amp;s=digital-text&amp;sprefix=kubernetes+best+practice%2Cdigital-text%2C64&amp;sr=1-1">Kubernetes Best Practices</a></li> -</ul> -<h2 id="up-next" >Up next -<span> - <a href="#up-next"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><ul> -<li><input disabled="" type="checkbox"> <a href="https://www.amazon.com/Self-Taught-Computer-Scientist-Beginners-Science/dp/1119724414/ref=sr_1_1?keywords=the+self+taught+computer+scientist&amp;qid=1659346654&amp;sprefix=the+self+taught+computer+%2Caps%2C82&amp;sr=8-1">The Self-Taught Computer Scientist</a></li> -<li><input disabled="" type="checkbox"> <a href="https://www.amazon.com/Unix-Programming-Environment-Prentice-Hall-Software/dp/013937681X/ref=sr_1_2?keywords=unix+programming+environment&amp;qid=1672841245&amp;s=books&amp;sprefix=unix+program%2Cstripbooks%2C104&amp;sr=1-2&amp;ufe=app_do%3Aamzn1.fos.18630bbb-fcbb-42f8-9767-857e17e03685">The Unix Programming Environment</a></li> -</ul> - - - + http://localhost:1313/about/ + My name is Ryan Nemeth and this is my personal blog. I write down my thoughts regarding Microsoft Azure, Kubernetes, cloud-native technologies, and software development. I find that documenting these things not only helps others but also helps reinforce my own knowledge as well. I may also blog about life or other random things from time to time. This blog has had many lives over the years. It originally started as a Blogger blog way back in 2012, moved to Wordpress for a while, then back to blogger, then to Ghost (running on a small droplet over @ DigitalOcean), then back to Wordpress again, and now here on Github pages. + diff --git a/public/js/coder.js b/public/js/coder.js new file mode 100644 index 00000000..9b46cfc3 --- /dev/null +++ b/public/js/coder.js @@ -0,0 +1,97 @@ +const body = document.body; +const darkModeToggle = document.getElementById('dark-mode-toggle'); +const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); + +// Check if user preference is set, if not check value of body class for light or dark else it means that colorscheme = auto +if (localStorage.getItem("colorscheme")) { + setTheme(localStorage.getItem("colorscheme")); +} else if (body.classList.contains('colorscheme-light') || body.classList.contains('colorscheme-dark')) { + setTheme(body.classList.contains("colorscheme-dark") ? "dark" : "light"); +} else { + setTheme(darkModeMediaQuery.matches ? "dark" : "light"); +} + +if (darkModeToggle) { + darkModeToggle.addEventListener('click', () => { + let theme = body.classList.contains("colorscheme-dark") ? "light" : "dark"; + setTheme(theme); + rememberTheme(theme); + }); +} + +darkModeMediaQuery.addListener((event) => { + setTheme(event.matches ? "dark" : "light"); +}); + +document.addEventListener("DOMContentLoaded", function () { + let node = document.querySelector('.preload-transitions'); + node.classList.remove('preload-transitions'); +}); + +function setTheme(theme) { + body.classList.remove('colorscheme-auto'); + let inverse = theme === 'dark' ? 'light' : 'dark'; + body.classList.remove('colorscheme-' + inverse); + body.classList.add('colorscheme-' + theme); + document.documentElement.style['color-scheme'] = theme; + + function waitForElm(selector) { + return new Promise(resolve => { + if (document.querySelector(selector)) { + return resolve(document.querySelector(selector)); + } + + const observer = new MutationObserver(mutations => { + if (document.querySelector(selector)) { + resolve(document.querySelector(selector)); + observer.disconnect(); + } + }); + + observer.observe(document.body, { + childList: true, + subtree: true + }); + }); + } + + if (theme === 'dark') { + const message = { + type: 'set-theme', + theme: 'github-dark' + }; + waitForElm('.utterances-frame').then((iframe) => { + iframe.contentWindow.postMessage(message, 'https://utteranc.es'); + }) + + } + else { + const message = { + type: 'set-theme', + theme: 'github-light' + }; + waitForElm('.utterances-frame').then((iframe) => { + iframe.contentWindow.postMessage(message, 'https://utteranc.es'); + }) + + } + + function sendMessage(message) { + const iframe = document.querySelector('iframe.giscus-frame'); + if (!iframe) return; + iframe.contentWindow.postMessage({ giscus: message }, 'https://giscus.app'); + } + sendMessage({ + setConfig: { + theme: theme, + }, + }); + + // Create and send event + const event = new Event('themeChanged'); + document.dispatchEvent(event); +} + +function rememberTheme(theme) { + localStorage.setItem('colorscheme', theme); +} diff --git a/public/js/script.32e751300d2d69e2cb56a98d2c9d964d54a53a8fb7281ccdbd80f055c88e8d86.js b/public/js/script.32e751300d2d69e2cb56a98d2c9d964d54a53a8fb7281ccdbd80f055c88e8d86.js new file mode 100644 index 00000000..e772f520 --- /dev/null +++ b/public/js/script.32e751300d2d69e2cb56a98d2c9d964d54a53a8fb7281ccdbd80f055c88e8d86.js @@ -0,0 +1,64 @@ +/* +This file has been taken from following blogpost with some modifications: +https://koki-nakamura22.github.io/blog/2019/10/03/hugo-adding-copy-button/ +Many thanks to Koki Nakamura! +*/ + +document.addEventListener("DOMContentLoaded", function(event) { + 'use strict'; + + if(!document.queryCommandSupported('copy')) { + return; + } + + let svgCopyCode = ''; + let svgSuccessCode = ''; + let svgFailCode = ''; + + function changeIcon(el, innerHtml) { + el.innerHTML = innerHtml; + setTimeout(() => { + el.innerHTML = svgCopyCode; + }, 1000); + } + + function selectText(node) { + let selection = window.getSelection(); + let range = document.createRange(); + if (node.childElementCount === 2) { + // Skip the title. + range.selectNodeContents(node.children[1]); + } else { + range.selectNodeContents(node); + } + selection.removeAllRanges(); + selection.addRange(range); + return selection; + } + + function addCopyButton(containerEl) { + let copyBtn = document.createElement("button"); + copyBtn.className = "highlight-copy-btn"; + copyBtn.innerHTML = svgCopyCode; + + let codeEl = containerEl.firstElementChild; + copyBtn.addEventListener('click', () => { + try { + let selection = selectText(codeEl); + document.execCommand('copy'); + selection.removeAllRanges(); + + changeIcon(copyBtn, svgSuccessCode) + } catch(e) { + console && console.log(e); + changeIcon(copyBtn, svgFailCode) + } + }); + + containerEl.appendChild(copyBtn); + } + + // Add copy button to code blocks + let highlightBlocks = document.getElementsByClassName('highlight'); + Array.prototype.forEach.call(highlightBlocks, addCopyButton); +}, false); \ No newline at end of file diff --git a/public/js/script.672e2309c296e07c18bcd08b28d797a56222ff941d65f308fba3158c44885b14.js b/public/js/script.672e2309c296e07c18bcd08b28d797a56222ff941d65f308fba3158c44885b14.js new file mode 100644 index 00000000..64aec0cf --- /dev/null +++ b/public/js/script.672e2309c296e07c18bcd08b28d797a56222ff941d65f308fba3158c44885b14.js @@ -0,0 +1,64 @@ +/* +This file has been taken from following blogpost with some modifications: +https://koki-nakamura22.github.io/blog/2019/10/03/hugo-adding-copy-button/ +Many thanks to Koki Nakamura! +*/ + +document.addEventListener("DOMContentLoaded", function(event) { + 'use strict'; + + if(!document.queryCommandSupported('copy')) { + return; + } + + let svgCopyCode = ''; + let svgSuccessCode = ''; + let svgFailCode = ''; + + function changeIcon(el, innerHtml) { + el.innerHTML = innerHtml; + setTimeout(() => { + el.innerHTML = svgCopyCode; + }, 1000); + } + + function selectText(node) { + let selection = window.getSelection(); + let range = document.createRange(); + if (node.childElementCount === 2) { + // Skip the title. + range.selectNodeContents(node.children[1]); + } else { + range.selectNodeContents(node); + } + selection.removeAllRanges(); + selection.addRange(range); + return selection; + } + + function addCopyButton(containerEl) { + let copyBtn = document.createElement("button"); + copyBtn.className = "highlight-copy-btn"; + copyBtn.innerHTML = svgCopyCode; + + let codeEl = containerEl.firstElementChild; + copyBtn.addEventListener('click', () => { + try { + let selection = selectText(codeEl); + document.execCommand('copy'); + selection.removeAllRanges(); + + changeIcon(copyBtn, svgSuccessCode) + } catch(e) { + console && console.log(e); + changeIcon(copyBtn, svgFailCode) + } + }); + + containerEl.appendChild(copyBtn); + } + + // Add copy button to code blocks + let highlightBlocks = document.getElementsByClassName('highlight'); + Array.prototype.forEach.call(highlightBlocks, addCopyButton); +}, false); diff --git a/public/page/1/index.html b/public/page/1/index.html index daf35cfc..0e4714b1 100644 --- a/public/page/1/index.html +++ b/public/page/1/index.html @@ -1,10 +1,10 @@ - https://rnemeth90.github.io/ - + http://localhost:1313/ + - + diff --git a/public/page/2/index.html b/public/page/2/index.html index 7e6e7b92..a6b0817f 100644 --- a/public/page/2/index.html +++ b/public/page/2/index.html @@ -3,7 +3,7 @@ - + @@ -19,9 +19,9 @@ - - - + + + - - + + + - + + + + + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - - + + + + + + + - - - - - - - - - @@ -115,348 +84,202 @@ - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    User Account Control

    - - -
    -
    -
    -

    Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system.

    +

    Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system.

    For a standard user, a token with the most basic privileges is assigned. Administrators have two tokens assigned, the first token contains all privileges usually awarded to an administrator (unrestricted), and the second is similar to that awarded to a basic user. This way, all programs that the administrator runs, including the Windows Shell, are run in basic user mode (this is why administrators still receive UAC prompts, but do not get asked for credentials). When an application requests higher privileges, the higher integrity token is used .

    User Account Control prompts each have their own meaning based on the color (blue, grey, yellow, or red. The blue prompt (Figure 1) means that a built in Windows component that is signed by Microsoft is requesting administrative privileges to continue. This prompt has a multicolored shield in the upper left corner. The grey prompt (Figure 2) means a software application that is signed by a third party developer is requesting admin privileges. This prompt has a yellow shield with a black exclamation mark in the upper left corner. The yellow prompt (Figure 3) signifies that a unsigned executable is requesting administrator privileges. This prompt also had a yellow shield with black exclamation mark in the upper left corner, and looks somewhat generic. Finally, the red prompt (Figure 4) means a program that was specifically blocked by an administrator has attempted to run.

    -

    +

    Figure 1

    -

    +

    Figure 2

    -

    +

    Figure 3

    -

    +

    Figure 4

    -
    - - - - + - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2012-11-15-user-account-control/index.html b/public/posts/2012-11-15-user-account-control/index.html index 467f6398..7d75b11e 100644 --- a/public/posts/2012-11-15-user-account-control/index.html +++ b/public/posts/2012-11-15-user-account-control/index.html @@ -1,112 +1,81 @@ + - - - - - - - + + + User Account Control · GeekyRyan + + - - -User Account Control - GeekyRyan - - - - - - - - - + - - - + + + - + + + + + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - - + + + + + + + - - - - - - - - - @@ -115,346 +84,202 @@ - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    User Account Control

    - - -
    -
    -
    -

    Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system.

    +

    Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system.

    For a standard user, a token with the most basic privileges is assigned. Administrators have two tokens assigned, the first token contains all privileges usually awarded to an administrator (unrestricted), and the second is similar to that awarded to a basic user. This way, all programs that the administrator runs, including the Windows Shell, are run in basic user mode (this is why administrators still receive UAC prompts, but do not get asked for credentials). When an application requests higher privileges, the higher integrity token is used.

    User Account Control prompts each have their own meaning based on the color (blue, grey, yellow, or red. The blue prompt (Figure 1) means that a built in Windows component that is signed by Microsoft is requesting administrative privileges to continue. This prompt has a multicolored shield in the upper left corner. The grey prompt (Figure 2) means a software application that is signed by a third party developer is requesting admin privileges. This prompt has a yellow shield with a black exclamation mark in the upper left corner. The yellow prompt (Figure 3) signifies that a unsigned executable is requesting administrator privileges. This prompt also had a yellow shield with black exclamation mark in the upper left corner, and looks somewhat generic. Finally, the red prompt (Figure 4) means a program that was specifically blocked by an administrator has attempted to run.

    -

    +

    Figure 1

    -

    +

    Figure 2

    -

    +

    Figure 3

    -

    +

    Figure 4

    -
    - - - - + - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2012-11-16-layer-2-switching-fundamentals/index.html b/public/posts/2012-11-16-layer-2-switching-fundamentals/index.html index ba8c37e9..73f37264 100644 --- a/public/posts/2012-11-16-layer-2-switching-fundamentals/index.html +++ b/public/posts/2012-11-16-layer-2-switching-fundamentals/index.html @@ -1,115 +1,84 @@ + - - - - - - - + + + Layer 2 Switching Fundamentals · GeekyRyan + + - - -Layer 2 Switching Fundamentals - GeekyRyan - - - - - - - - - + - - - + + + - + + + + + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - - + + + + + + + - - - - - - - - - @@ -118,348 +87,211 @@ - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - -
    -
    - - - -
    -
    -
    -

    Layer 2 Switching Fundamentals

    - - -
    -
    -
    -

    Switches are devices that support a large number of ports to connect devices to the network.

    -

    Design: - - - - - -

    -

    More towards a CCNP or CCDA topic, but designing a network when it comes to the switching side can be done in three building blocks. The access layer, the distribution layer, and the core layer. The access layer generally has a high port density, can support VLANs, QoS, and access lists. The distribution layer will aggregate multiple access layer switches. These are also generally Layer 3 switches to allow routing among an enterprise. It will need to be able to handle the volume of traffic in addition to supporting the same features as the access layer switches. The core layer is the device which will need the highest bandwidth backplane to deal with all of the traffic.

    -

    How switches handle traffic: - - - - - -

    A switch is an intelligent device that can make some decisions on how to handle the data it is given. Switches can be divided into two categories for these decisions: Layer 2 or Layer 3 switches. For the CCNA we will only be interested in the layer 2 switches. Layer 2 switches operate at the data link layer. This layer deals primarily with MAC addresses. A Layer 2 switch will build a CAM table full of dynamically learned MAC addresses. The way it learns these addresses is by inspecting the layer 2 header/trailer and learning the source MAC addresses on the frames it receives. A frame is what a packet is encapsulated in when it moves from device to device across the network.

    -

    -

    With this example the switch has learned PC1/PC2/and PC3′s MAC addresses. If a packet came in on Fa0/4 from PC4, the switch would look at the source MAC address and put an entry for 4444.4444.4444 on Fa0/4. A switch will route traffic based on this table. There are a few decisions it must make to determine how to handle traffic. When it first receives a frame it will consult it’s CAM table to determine whether or not it has the source MAC address listed for that port. If not, it will add it to the CAM table. In the example above, PC1 sent a frame to the switch, the switch noticed PC1′s MAC address was not in it’s table and added it. The next thing it looks at is the destination MAC address. The CAM table is again consulted. If it finds a match the switch will send the frame directly to the recipient it needs to on whatever port it is on. In the example above, PC1 sends a frame to PC3. Because the switch sees 1111.1111.1111 sending to 3333.3333.3333 and has an entry for 3333.3333.3333 it will send the frame out of port Fa0/3 to the recipient. If a destination is not in the CAM table the switch will need to try to find the recipient. In this case the switch will decide to broadcast the frame out of every port EXCEPT the one it came in on. In this example, PC1 sends a frame destined for PC4. The switch will see a frame from 1111.1111.1111 to 4444.4444.4444. PC4′s MAC address is not in it’s table. The switch will then send the frame out of every port except for Fa0/1 (the source). When PC2 and PC3 get this frame, it will determine if the frame was meant for it, and if not it will ignore it. PC4 will also make the same decision and PC4 will respond. Once PC4 has responded the switch will be able to add PC4′s MAC address to it’s table on Fa0/4.

    - -
    - - - - - - +
    - - - + - - - - - - +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/posts/2014-11-15-file-history/index.html b/public/posts/2014-11-15-file-history/index.html index 3cd74a34..a24db46c 100644 --- a/public/posts/2014-11-15-file-history/index.html +++ b/public/posts/2014-11-15-file-history/index.html @@ -1,112 +1,81 @@ + - - - - - - - + + + File History · GeekyRyan + + - - -File History - GeekyRyan - - - - - - - - - + - - - + + + - + + + + + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - - + + + + + + + - - - - - - - - - @@ -115,346 +84,198 @@ - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    File History

    - - -
    -
    -
    -

    File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. To begin using it, connect an external drive and search for File History on the Start Screen:

    -

    +

    File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. To begin using it, connect an external drive and search for File History on the Start Screen:

    +

    After opening File History, you will see this screen:

    -

    +

    To enable File History, click the ‘Turn On’ button. You can select the drive you want to use by clicking ‘Select Drive’ on the left hand side from this same screen. The first time you enable File History, it will create a full backup of all files on your computer, except for files that you do not access (system files), and files you have chosen to exclude. From then on, it will create a versioned copy of every file that has changed since the last backup.

    You can use a locally attached drive or a network share for File History. To choose how often File History backs up files; choose ‘Advanced Settings’. From here you can also choose how much space on the drive is used, and how long saved versions of files should be kept.

    When the total space allocated to File History has been used, the feature will delete the oldest versions of files to make room for newer versions.

    -
    - - - - + - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2014-11-16-branchcache/index.html b/public/posts/2014-11-16-branchcache/index.html index f4270c01..68f2fc4d 100644 --- a/public/posts/2014-11-16-branchcache/index.html +++ b/public/posts/2014-11-16-branchcache/index.html @@ -1,112 +1,81 @@ + - - - - - - - + + + BranchCache · GeekyRyan + + - - -BranchCache - GeekyRyan - - - - - - - - - + - - - + + + - + + + + + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - - + + + + + + + - - - - - - - - - @@ -115,345 +84,206 @@ - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    BranchCache

    - - -
    -
    -
    -

    Branchcache is a technology unique to Windows 7 and Windows Server 2008 R2. It provides faster connection to shared files across wide area networks. Branchcache works by caching content hosted on remote servers on a local caching server in the LAN. When a client queries for data on a remote server, it first looks in the local caching server. If the data is not found there, the remote server is accessed and transfer’s the data to the local caching server, where it is then accessed by the client who originally made the request. That way, all future client requests will not have to go across the wide area network, rather opting to access the local caching server until the data changes.

    +

    Branchcache is a technology unique to Windows 7 and Windows Server 2008 R2. It provides faster connection to shared files across wide area networks. Branchcache works by caching content hosted on remote servers on a local caching server in the LAN. When a client queries for data on a remote server, it first looks in the local caching server. If the data is not found there, the remote server is accessed and transfer’s the data to the local caching server, where it is then accessed by the client who originally made the request. That way, all future client requests will not have to go across the wide area network, rather opting to access the local caching server until the data changes.

    Branchcache is only available on Windows 7 clients running Enterprise or Ultimate, and Windows Server 2008 R2. Branchcache becomes active when the round trip latency time from client to remote server exceeds 80 milliseconds.

    Branchcache is available in two modes: distributed cache mode and hosted cache mode. What you just read above was the basics of hosted cached mode. Distributed cache mode works differently to achieve the same results. When a client accesses data across the WAN, it stores that data in its own cache. This way, if another client needs access to the data, it can retrieve it locally. Also, this allows each client to host part of the cache, rather than one machine hosting the entire cache.

    There are two steps to configuring Branchcache on a Windows 7 client. I will not include the server configuration at this point in time.

    Enable Branchcache (Hosted or Distributed, Server 08 R2 will be required for Hosted mode)

    Configure the appropriate ports within the Windows Firewall

    You can enable Branchcache from within Group Policy or by using the Netsh command. When using Group Policy, navigate to Computer Configuration > Administrative Templates > Network > Branchcache. From here you can turn on Branchcache and enable the mode you want to use. You can also set the percentage of disk space to be used for caching. After this, open the Windows Firewall and unblock the Branchcache ports. You only need to do this when configuring Branchcache via Group Policy. Using the Netsh command automatically configures the firewall. Here are the basic commands for Netsh:

    -
    Netsh Branchcache set service mode=distributed
    -
    -Netsh Branchcache reset
    -
    -Netsh Branchcache show status
    -
    -Netsh Branchcache set cachesize
    +
    Netsh Branchcache set service mode=distributed
    +
    +Netsh Branchcache reset
    +
    +Netsh Branchcache show status
    +
    +Netsh Branchcache set cachesize
     

    *Configuring Branchcache must be done from an administrative command prompt.

    -
    - +
    - - - - -
    - - - - - - - + + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2014-11-16-tcpip-network-fundamentals/index.html b/public/posts/2014-11-16-tcpip-network-fundamentals/index.html index 3de18f63..53e68dd1 100644 --- a/public/posts/2014-11-16-tcpip-network-fundamentals/index.html +++ b/public/posts/2014-11-16-tcpip-network-fundamentals/index.html @@ -1,235 +1,196 @@ + - - - - - - - + + + TCP/IP Network Fundamentals · GeekyRyan + + - + -TCP/IP Network Fundamentals - GeekyRyan + + + + + + + - - - - - - - - + + + + + + + + + + - + + + + - - - - - + + + - - - + - + + + - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    TCP/IP Network Fundamentals

    - - -
    -
    -
    -

    Going over the basics of network fundamentals and all the models and ideas behind them. The most pushed idea is the OSI networking model which consists of 7 layers, all of which deal with a certain aspect of the networking model.

    +

    Going over the basics of network fundamentals and all the models and ideas behind them. The most pushed idea is the OSI networking model which consists of 7 layers, all of which deal with a certain aspect of the networking model.

    A P S T N D P

    From the top down this represents the following

    Layer 7: Application – This layer is the channel between software and external requests. For example, a web server would work with this layer to process HTTP requests.

    @@ -247,242 +208,104 @@

    TCP/IP Network Fundamentals

    Collision Domain – The bounds where a collision may occur. This is relevant for networks utilizing half-duplex communication and for older devices such as hubs.

    Broadcast Domain – The bounds where a broadcast can reach.

    Collision Domains: Forgive the visio art, it will get better… hopefully

    -

    -

    <span style=“color: windowtext; font-family: “Verdana”,sans-serif; font-size: 9.0pt; mso-no-proof: yes; text-decoration: none; text-underline: none;">

    +

    +

    <span style=“color: windowtext; font-family: “Verdana”,sans-serif; font-size: 9.0pt; mso-no-proof: yes; text-decoration: none; text-underline: none;">

    Every computer connected to that hub is in the collision domain noted by the circle. With a hub, the signal gets sent to every device connected to it, regardless of whether it was meant to go to that machine or not. When the PC at the top left sends information at the same time as the PC on the bottom right, a collision is likely to occur

    -

    <span style=“color: windowtext; font-family: “Verdana”,sans-serif; font-size: 9.0pt; mso-no-proof: yes; text-decoration: none; text-underline: none;">

    -

    +

    <span style=“color: windowtext; font-family: “Verdana”,sans-serif; font-size: 9.0pt; mso-no-proof: yes; text-decoration: none; text-underline: none;">

    +

    Every computer connected to this switch is limited in its collision domain to the port on the switch and the network card in the PC. The reason being that switches do not just take a signal and send it out of all the ports, it is intelligent enough to be able to send information directly to the PC it needs to. This is further mitigated by the fact that a computer connected to a switch may operate at full-duplex, allowing both simultaneous sending and receiving of information.

    Collisions and how they are handled:

    The way computers avoid collision in this sense is via something called CSMA/CD or Carrier Sense Multiple Access/Collision Avoidance. The way it works is this, a computer will wait until the line is silent before sending information. Every computer will listen to determine whether the line is truly clear. If two computers were to send at the same time, and a collision were to occur, the computers will immediately trigger a random back off time in which they will not try resending that information until the timer is up.

    Unicast vs Broadcast vs Multicast

    The idea between these concepts is fairly simple. Unicast deals with a transmission that is intended for one recipient. A broadcast is a transmission that is meant for all recipients that are able to hear it. Multicast is intended for a specific group of recipients.

    -
    - - - + - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2014-11-17-creating-applocker-policies/index.html b/public/posts/2014-11-17-creating-applocker-policies/index.html index 48ed31af..a546b466 100644 --- a/public/posts/2014-11-17-creating-applocker-policies/index.html +++ b/public/posts/2014-11-17-creating-applocker-policies/index.html @@ -1,235 +1,196 @@ + - - - - - - - + + + Creating Applocker Policies · GeekyRyan + + - + -Creating Applocker Policies - GeekyRyan + + + + + + + - - - - - - - - + + + + + + + + + + - + + + + - - - - - + + + - - - + - + + + - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Creating Applocker Policies

    - - -
    -
    -
    -

    Application Control Policies can be used to restrict what programs a user is allowed to run. They can be created at the local Group Policy level or the Domain GPO level. There are 4 different types of Applocker RULES that you can implement, depending on what type of executable you want to control access to.

    +

    Application Control Policies can be used to restrict what programs a user is allowed to run. They can be created at the local Group Policy level or the Domain GPO level. There are 4 different types of Applocker RULES that you can implement, depending on what type of executable you want to control access to.

    Executable Rules – EXE’s, COM’s, etc.

    Script Rules – batch files, VB scripts, etc.

    AppX Rules – AppX Packages (Windows 8.1/Server 2012 R2 Metro Interface programs)

    @@ -237,244 +198,106 @@

    Creating Applocker Policies

    After choosing what type of executable file you want to control, you can choose the corresponding rule type. Then, you will be able to choose the criteria for that rule type. Applocker rule criteria are things such as file path, publisher, and file hash. Criteria allow you to be more granular with your selections. Rather than saying you want to block access to ALL executable’s on a computer, you can choose to block access to executable’s published by a certain vendor, or found in a specified directory.

    Applocker can be found in the Group Policy Editor at: Computer Configuration\Windows Settings\Security Settings. Application Control Policies. By right-clicking on the Applocker node, you can configure rule enforcement. You have the option to enforce rules or audit rules based on rule type. Auditing will allow

    you get a good grasp on what Applocker will do in your environment if you are unsure.

    -

    +

    Clicking the Advanced tab of this window will allow you to configure rule enforcement for Dynamic Link Libraries. It’s best to leave DLL rule enforcement disabled, because it can cause a system to suffer dramatic performance hits.

    Underneath the Applocker node, you will find nodes for the 4 different rule types. You can create new rules by right clicking on any of these nodes and clicking “Create New Rule”. Before creating any rules, I advise you to create the default rules. Doing this will ensure that users are still able to run programs in the Program Files directory and the Windows directory. Also, members of the built-in Administrators group will be allowed to run ANY files.

    When creating custom Applocker rules, you can choose to allow or deny the program, and what group the rule will apply to (by default, the “Everyone” special identity is always selected).

    You will also be able to choose the criteria for the executable that you are controlling.

    -

    +

    If the executable has a digital signature from the software publisher, choose “Publisher”. Doing so will give you even more options:

    -

    +

    This allows you to really drill down and get granular with the rule. Microsoft allows us to control access to the file based on the Publisher, the Product Name, the File Name, and even the File Version.

    Creating rules based on File Path criteria is not advised, being that if the file jumps directories, the rule will no longer apply. I also don’t advise using the File Hash criteria. My reason behind this is, if the file gets updated, the hash changes. If that happens, the rule is no longer valid.

    After choosing the criteria type you would like to use, you can choose to create exceptions, if any. When multiple rules conflict, the order of precedence is Publisher, File Hash, and then File Path. So Publisher rules will always override File Hash rules, File Hash rules will always override File Path rules, and you get the point…

    Finally, in order for your endpoint workstations to process Applocker rules, the Application Identity Service must be running. I like to control this with the same GPO that I configure Applocker in.

    -
    - - - + - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/index.html b/public/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/index.html index 8115f271..de4a9493 100644 --- a/public/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/index.html +++ b/public/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/index.html @@ -1,112 +1,82 @@ + - - - - - - - + + + The Case of Transitive Trusts and Dropped RPC Connections · GeekyRyan + + - - -The Case of Transitive Trusts and Dropped RPC Connections - GeekyRyan - - - - - - - - - + - - - + + + - + + + + + + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - - + + + + + + + - - - - - - - - - @@ -115,346 +85,199 @@ - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    The Case of Transitive Trusts and Dropped RPC Connections

    - - -
    -
    -
    -

    I was at a client earlier this morning, working to get a transitive forest trust setup between their two domains. Setting up the trust on ServerA to DomainB went without issue. However, when trying to create the trust between ServerB and DomainA, I received this error: The secure channel reset on Active Directory Domain Controller (Your domain controller) of domain (Your domain) to domain (your other domain) failed with error: RPC server is unavailable.

    +

    I was at a client earlier this morning, working to get a transitive forest trust setup between their two domains. Setting up the trust on ServerA to DomainB went without issue. However, when trying to create the trust between ServerB and DomainA, I received this error: The secure channel reset on Active Directory Domain Controller (Your domain controller) of domain (Your domain) to domain (your other domain) failed with error: RPC server is unavailable.

    Troubleshooting (as always) started off with the basics: is the firewall on or off, are the services running, are the names being properly resolved, etc. Well, the Windows Firewall on both servers was off and the RPC services were running. So what now?? I fired up NMAP on ServerB and did a syn scan on ServerA. After reviewing the output, I could see that the ports were open. I then went over to ServerA and opened up the Services MSC console. The RPC services appeared to be running. Being that they are system services and you cannot manually interact with them, I was unable to manually restart them. Just out of curiosity,

    I opened a command prompt while connected to that server and ran Netstat -A. This is when I had the “AHA!” moment. Nothing was listening on any of the RPC ports! I rebooted the server (something I don’t really like to do..), logged in and ran Netstat -A again. This time, RPC was listening. I went back over to ServerB, walked through the New Trust Wizard, and success! Oh, the feeling of victory!

    -
    - - - - + - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2014-12-08-dhcp-address-negotiation-process/index.html b/public/posts/2014-12-08-dhcp-address-negotiation-process/index.html index 2cb53391..5b77d829 100644 --- a/public/posts/2014-12-08-dhcp-address-negotiation-process/index.html +++ b/public/posts/2014-12-08-dhcp-address-negotiation-process/index.html @@ -1,112 +1,82 @@ + - - - - - - - + + + DHCP Address Negotiation Process · GeekyRyan + + - - -DHCP Address Negotiation Process - GeekyRyan - - - - - - - - - + - - + + + - - + + + + + + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - - + + + + + + + - - - - - - - - - @@ -115,343 +85,196 @@ - - - - Skip to main content -
    -
    - - - - - - - - - - -
    -
    - - - - - - - - - - + - - - - - - +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/index.html b/public/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/index.html index c20246ef..091f771d 100644 --- a/public/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/index.html +++ b/public/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/index.html @@ -1,475 +1,296 @@ + - - - - - - - + + + Powershell: SID to Username · GeekyRyan + + - + -Powershell: SID to Username - GeekyRyan - - + + + - - + + + - + + + + + + + + + + + + - - + + + + + + + - - - - - - - - - + - + + - - - - - - - - - - - - + + + + + + - - - - - - + + - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - -
    -
    - - - -
    -
    -
    -

    Powershell: SID to Username

    - - -
    -
    -
    -

    This is a simple script to convert a SID to a username

    -
    # Returns a username based on a SID
    -# Author: Ryan Nemeth
    -# Date: 12/2/2014
    -
    -$SID = read-host Please enter the SID: 
    -$object = New-Object System.Security.Principal.SecurityIdentifier($SID)
    -$User = $object.Translate( \[System.Security.Principal.NTAccount\])
    -write-host The user is:  $User.Value
    -
    -
    - - - - - - - +
    - - - - - - + - - - - - - +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/posts/2014-12-08-unlock-domain-user-from-cmd-line/index.html b/public/posts/2014-12-08-unlock-domain-user-from-cmd-line/index.html index 6d4782b4..c4e042ef 100644 --- a/public/posts/2014-12-08-unlock-domain-user-from-cmd-line/index.html +++ b/public/posts/2014-12-08-unlock-domain-user-from-cmd-line/index.html @@ -1,118 +1,87 @@ + - - - - - - - + + + Unlock a Domain User from CMD Line · GeekyRyan + + - + -Unlock a Domain User from CMD Line - GeekyRyan + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - + + + - - - - - + - + + + - - - - - - - - - - - - + + + + + - - - - - - - - - + + @@ -122,347 +91,199 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - -
    -
    - - - - - - - - - - + - - - - - - +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/posts/2015-03-09-ping-sweeping-with-fping/index.html b/public/posts/2015-03-09-ping-sweeping-with-fping/index.html index 33280fea..2b065820 100644 --- a/public/posts/2015-03-09-ping-sweeping-with-fping/index.html +++ b/public/posts/2015-03-09-ping-sweeping-with-fping/index.html @@ -1,467 +1,296 @@ + - - - - - - - + + + Ping Sweeping with FPing · GeekyRyan + + - + -Ping Sweeping with FPing - GeekyRyan - - + + + - - + + + - + + + + + + + + + + + + + - - + + + + + + + - - - - - - - - - + - + + - - - - - - - - - - - - + + + + + + - - - - - - + + - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - -
    -
    - - - -
    -
    -
    -

    Ping Sweeping with FPing

    - - -
    -
    -
    -

    I generally use NMAP for any type of host discovery, but recently started experimenting with FPing. One thing I found is that, when performing a ping sweep, not only do I see the hosts that replied to the ping, but FPing also sends any unreachable IP addresses to stdout (which is super annoying and ugly if you ask me…).

    -

    -

    Anyway, after a bit of research, I found a nifty way to suppress these messages. Linux allows us to redirect all error messages to /dev/null. So instead of just running the vanilla fping -a -g…. you would run the program and output all error messages /dev/null, like so:

    -

    - -
    - - - - - - - +
    - - - - - - + - - - - - - +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/posts/2015-08-12-failed-to-mount-exchange-2010-database/index.html b/public/posts/2015-08-12-failed-to-mount-exchange-2010-database/index.html index e29d7f3d..d02eb048 100644 --- a/public/posts/2015-08-12-failed-to-mount-exchange-2010-database/index.html +++ b/public/posts/2015-08-12-failed-to-mount-exchange-2010-database/index.html @@ -1,480 +1,297 @@ + - - - - - - - + + + Failed to Mount Exchange 2010 Database · GeekyRyan + + - - -Failed to Mount Exchange 2010 Database - GeekyRyan - - - - - - + - - - - - - + + + - + + + + + + + + + + + + + + - - - - - - - - + + + + - + + + - + - - - + + - - - + + + + - - - - - - + + + + - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Failed to Mount Exchange 2010 Database

    - - -
    -
    -
    -

    Recently, one of my users’ came to me and said he was missing two months worth of email. This was just after migrating to Exchange Online. We were using Exchange 2010 with System Center DPM for backups.

    +

    Recently, one of my users’ came to me and said he was missing two months worth of email. This was just after migrating to Exchange Online. We were using Exchange 2010 with System Center DPM for backups.

    I restored the database that the users’ mailbox was on from a backup then copied it over to the Exchange server from the network share I restored it to. All was going well, until I tried to mount the darn thing.

    I was getting this error and could not for the life of me decry-pt the meaning of it. There is obviously some type of IO issue/file not found. But what could it be?

    -

    +

    I figured I’d better kick this one off with some basic troubleshooting. First, I checked the health of the database and made sure it was clean. Passed that test…

    -

    +

    Then ran a repair on the database, to no avail.

    -

    +

    After racking my brain for a good thirty minutes, and a few failed Google searches, I found the solution. It was so simple! I created the log file directory in the folder with the database, and voila, the database mounted without a single error!

    -

    -

    +

    +

    I was able to see the ‘supposed’ location of the log file by opening the Exchange Management Shell and running the ‘Get-MailboxDatabase’ cmdlet, like so:

    Get-MailBoxDatabase –Identity | FL Name, ServerName, EDBFilePath, LogFolderPath

    -

    +

    I’m not sure why the database mounting process isn’t capable of creating the log file directory… I think Microsoft would have thought and planned for a situation like this. Hope this helps!

    -
    - + - - - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2015-08-13-error-when-reinstalling-dirsync/index.html b/public/posts/2015-08-13-error-when-reinstalling-dirsync/index.html index 3d0fece8..d4ad54a3 100644 --- a/public/posts/2015-08-13-error-when-reinstalling-dirsync/index.html +++ b/public/posts/2015-08-13-error-when-reinstalling-dirsync/index.html @@ -1,489 +1,308 @@ + - - - - - - - + + + Error When Reinstalling DirSync · GeekyRyan + + - - -Error When Reinstalling DirSync - GeekyRyan - - - - - - + - - - - - - + + + - + + + + + + + + + + + + + + + - - - - - - - - + + + + - + + + - + - - - + + - - - + + + + - - - - - - + + + + - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Error When Reinstalling DirSync

    - - -
    -
    -
    -

    Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process:

    -

    +

    Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process:

    +

    I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do:

    • Uninstall Windows Azure Active Directory Sync tool and reboot -
    • +

    Remove this directory and all subfolders: C:Program FilesWindows Azure Active Directory Sync -

    +

    If you created a domain account to use for DirSync, remove it. Also remove the Office 365 account you created.

    • Delete the Group accounts that the DirSync wizard created. Their names all begin with “FIM”
    -

    +

    Uninstall MSSQL:

    • Delete the MSSQL directory: C:Program FilesMicrosoft SQL Server
    • Reboot!
    • You should be able to install and configure DirSync now.
    -

    +

    -
    - + - - - - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/index.html b/public/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/index.html index 190b78fe..874b9569 100644 --- a/public/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/index.html +++ b/public/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/index.html @@ -1,507 +1,328 @@ + - - - - - - - + + + Script for Querying All AD Computers Time Source · GeekyRyan + + - + -Script for Querying All AD Computers Time Source - GeekyRyan - - + + + - - + + + - + + + + + + + + + + + + + - - + + + + + + + - - - - - - - - - + - + + - - - - - - - - - - - - + + + + + + - - - - - - + + - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - -
    -
    - - - -
    -
    -
    -

    Script for Querying All AD Computers Time Source

    - - -
    -
    -
    -

    This script will iterate through all computers in Active Directory and return the configured time server for each computer.

    -
    <#
    -    .SYNOPSIS
    -     Get time source for all computers in domain
    -    .EXAMPLE
    -     Get-TimeSource
    -    .NOTES
    -     Author: Ryan Nemeth - RyanNemeth@live.com
    -     Site: http://www.geekyryan.com
    -    .LINK
    -     http://www.geekyryan.com
    -    .DESCRIPTION
    -     This function will iterate through all computers/servers in a domain and return the time source
    -     for each.
    -#>
    -
    -Write-Host -foregroundcolor Red -BackgroundColor black "This script must be run on a domain controller and requires that the AD Powershell module be installed"
    -
    -$module = Get-Module -ListAvailable | Select-Object -ExpandProperty Name
    -
    -if($module -notcontains "ActiveDirectory") {
    -    Write-Host -foregroundcolor red -backgroundcolor black "***Active Directory Powershell Module Not Found***"
    -}
    -else {
    -    Write-Host -foregroundcolor yellow "Found Active Directory Powershell Module. Importing..."
    -}
    -
    -Import-Module ActiveDirectory
    -
    -$computers = get-adcomputer -filter * | Select-Object -ExpandProperty Name
    -
    -foreach($computer in $computers) {
    -  $tm_source = w32tm /query /computer:$computer /source
    -  write-host "The time source for" $computer "is" $tm_source
    -}
    -

    - -
    - - - - - - +
    - - - - - - + - - - - - - +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/index.html b/public/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/index.html index 504530bc..728392fe 100644 --- a/public/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/index.html +++ b/public/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/index.html @@ -1,112 +1,82 @@ + - - - - - - - + + + Finding All Mailboxes with a Forwarding Address in Exchange 2003 · GeekyRyan + + - - -Finding All Mailboxes with a Forwarding Address in Exchange 2003 - GeekyRyan - - - - - - - - - + - - - + + + - + + + + + + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - - + + + + + + + - - - - - - - - - @@ -115,353 +85,200 @@ - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Finding All Mailboxes with a Forwarding Address in Exchange 2003

    - - -
    -
    -
    -

    Believe it or not, the MSP I work for still has a client who is using Exchange 2003 as their primary email service. Despite several attempts at convincing them of the power of Office 365, they refuse to migrate. Last week the CFO contacted me and requested we provide them with a report of all users who have their email forwarded to another mailbox. “Ok, no problem.” I said helpfully as the client informed me of their request (at the time I didn’t even think about them having Exchange 2003…). I figured I would just connect to their server and do some quick PowerShell magic, and that would be it. Quick and painless, right? Wrong.

    +

    Believe it or not, the MSP I work for still has a client who is using Exchange 2003 as their primary email service. Despite several attempts at convincing them of the power of Office 365, they refuse to migrate. Last week the CFO contacted me and requested we provide them with a report of all users who have their email forwarded to another mailbox. “Ok, no problem.” I said helpfully as the client informed me of their request (at the time I didn’t even think about them having Exchange 2003…). I figured I would just connect to their server and do some quick PowerShell magic, and that would be it. Quick and painless, right? Wrong.

    I did the RDP dance and got connected to their server, and my jaw just about hit the floor when I couldn’t find the Exchange Management Shell! I asked around the office to see if any of the other guys could help, but no one knew what to do. However, after talking with one of the guys, I remembered that this is Active Directory we are dealing with. There are objects, and those objects have attributes. The mailboxes/user accounts are objects, and those objects have attributes. So what attribute is it that controls forwarding addresses? I manually found one of the users who had a forwarding address configured. Then I opened up Active Directory Users and Computers, opened up her account properties, and went to the Attribute Editor tab. I filtered for attributes that have values and was able to see the email address that her mail was forwarding to. This was the “altRecipient” attribute.

    I then did an “Advanced” search in Active Directory Users and Computers for any objects that have the “altRecipient” attribute configured, like so:

    -

    +

    This search showed me all of the mailboxes that have an alternate recipient (forwarding address) configured. Not sure if there is another way to obtain this information, but this is the way that worked for me. Hopefully this article is able to help someone in the same situation.

    -
    - - - - + - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2015-10-15-azure-ad-connect-password-sync-disabled/index.html b/public/posts/2015-10-15-azure-ad-connect-password-sync-disabled/index.html index 82360766..7e57f530 100644 --- a/public/posts/2015-10-15-azure-ad-connect-password-sync-disabled/index.html +++ b/public/posts/2015-10-15-azure-ad-connect-password-sync-disabled/index.html @@ -1,230 +1,191 @@ + - - - - - - - + + + Azure AD Connect Password Sync &#8211; Disabled and Grayed Out · GeekyRyan + + - - -Azure AD Connect Password Sync &#8211; Disabled and Grayed Out - GeekyRyan - - - - - - + - - - - - - + + + - + + + + + + + + + + + + + - - - - - - - - + + + + - + + + - + - - - + + - - - + + + + - - - - - - + + + + - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Azure AD Connect Password Sync &#8211; Disabled and Grayed Out

    - - -
    -
    -
    -

    Ran into a problem earlier with the new Azure AD Connect Wizard. We had configured the wizard and synced around 500 AD accounts. However, password sync was not working. I opened the wizard to confirm the configuration and found that “Password Hash Synchronization” was disabled. It was greyed out and could not be enabled.

    -

    +

    Ran into a problem earlier with the new Azure AD Connect Wizard. We had configured the wizard and synced around 500 AD accounts. However, password sync was not working. I opened the wizard to confirm the configuration and found that “Password Hash Synchronization” was disabled. It was greyed out and could not be enabled.

    +

    I called Microsoft and worked for a couple hours with a technician to resolve the issue. Thought I should post the resolution here in case anyone else encounters this.

    You can enable password sync by running the following script:

    Import-Module ADSync

    @@ -235,239 +196,101 @@

    Azure AD Connect Password Sync &#8211; Disable

    get-ADSyncAADPasswordSyncConfiguration -sourceconnector $adConnector

    You need to set the value of the $adConnector and $aadConnector variables with the names of your Connectors found in the MIISClient.

    Open the MIISClient by browsing to:

    -

    +

    Right click on MIISClient.exe and click “Run As Administrator”.

    You can obtain the names of your connectors in by going to the Connectors tab and looking at the Names column. There are two values here that you need to pay attention to. The Windows Azure Active Directory connector is your Azure Connector (obviously), and the other connector is your on-prem connector.

    -

    +

    Now that you have the names, just plug them into the script and run it. You can go back to the Azure AD Connect Wizard and verify that password sync is enabled. You can also go to the Event Viewer -> Application log and look for events 576 and 577. These two events are related to password sync and should show you all AD accounts that have successfully synced passwords.

    You can force a sync by going to this location and running “DirectorySyncClientCmd.exe”.

    -

    +

    -

    - + - - - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/index.html b/public/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/index.html index 03882367..953b674d 100644 --- a/public/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/index.html +++ b/public/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/index.html @@ -1,476 +1,293 @@ + - - - - - - - + + + The User Profile Service service failed the logon · GeekyRyan + + - + -The User Profile Service service failed the logon - GeekyRyan + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + - - - - - - - - - + - + + + - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    The User Profile Service service failed the logon

    - - -
    -
    -
    -

    One of my clients had a really strange issue the other day. He has a domain admin account in his domain and was not able to login to a server that I recently built. The server was an Exchange 2013 box, and was used in Coexistence mode to migrate his company from an Exchange 2007 box.

    +

    One of my clients had a really strange issue the other day. He has a domain admin account in his domain and was not able to login to a server that I recently built. The server was an Exchange 2013 box, and was used in Coexistence mode to migrate his company from an Exchange 2007 box.

    He was getting this error message when attempting to login:

    -

    +

    This is a classic error message that I’m sure most technicians have seen before. Usually the resolution is to go into the registry and rename the user profile key to have a “.bak” extension and then do some other magic. However, this time, that was not the case. I looked in the registry and didn’t even see a reg key for his profile. I then looked in the c:users folder and didn’t see a folder for his profile. Strange…

    So what exactly was happening? Well, I took a look at the Event Viewer and found this error message:

    -

    +

    I browsed to the file referenced in the error message and deleted it. Walla! He was able to login with his admin account. I’m not sure why this file was in the default user profile. It has something to do with Customer Experience Improvement Program:

    -

    http://www.nextofwindows.com/what-is-sqmdata-and-sqm-file-in-windows-7-and-how-to-delete-them

    +

    http://www.nextofwindows.com/what-is-sqmdata-and-sqm-file-in-windows-7-and-how-to-delete-them

    -
    - - - + - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/index.html b/public/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/index.html index 0f3dc555..7fcbbb6c 100644 --- a/public/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/index.html +++ b/public/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/index.html @@ -1,115 +1,85 @@ + - - - - - - - + + + Script for Setting the License for Multiple Office 365 User Accounts · GeekyRyan + + - - -Script for Setting the License for Multiple Office 365 User Accounts - GeekyRyan - - - - - + - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + - - + + + - - - - - + - + + + - - - - - - - - - - - - + + + + + - - - - - - - - - + + @@ -119,352 +89,201 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - -
    -
    - - - -
    -
    -
    -

    Script for Setting the License for Multiple Office 365 User Accounts

    - - -
    -
    -
    -

    A script for setting the Office 365 license for multiple users. Requires a CSV file named users.csv. This file must in the same directory as the script. The CSV file must contain three columns. The title of the columns should be UPN, UsageLocation, and SKU.

    -

    BulkSet-MsolUserLicense.ps1

    - -
    - - - - - - - +
    - - - - - - + - - - - - - +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/posts/2016-10-04-exchange-2013-error-0x80070070-while/index.html b/public/posts/2016-10-04-exchange-2013-error-0x80070070-while/index.html index cc7ec1c8..90dc10f1 100644 --- a/public/posts/2016-10-04-exchange-2013-error-0x80070070-while/index.html +++ b/public/posts/2016-10-04-exchange-2013-error-0x80070070-while/index.html @@ -1,458 +1,279 @@ + - - - - - - - + + + Exchange 2013: Error 0x80070070 While Adding DAG Member · GeekyRyan + + - + -Exchange 2013: Error 0x80070070 While Adding DAG Member - GeekyRyan - - + + + - - + + + - + + + + + + + + + + - - + + + + + + + - - - - - - - - - + - + + - - - - - - - - - - - - + + + + + + - - - - - - + + - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - -
    -
    - - - -
    -
    -
    -

    Exchange 2013: Error 0x80070070 While Adding DAG Member

    - - -
    -
    -
    -

    Error: A server-side database availability group administrative operation failed. Error Failed to add or remove the Failover-Clustering feature. Error: The request to add or remove features on the specified server failed. A DISM session could not be opened. An error occurred accessing the temporary folder C:WindowsTEMP57ACE2DE-4CD2-4F5F-B7A0-93D867A89A12. Ensure that the path to the temporary folder exists and that you have Read/Write permissions on the folder. Error: 0x80070070

    -

    Solution: I was attempting to remotely add the DAG member from the ECP on my workstation. I logged into the server and found that the system drive was nearly full (~100MB free). Luckily this mailbox server was a virtual machine, and I was able to quickly expand the drive using VMM. After doing this I was able to successfully add the mailbox server to the DAG.

    - -
    - - - - - - - +
    - - - - - - + - - - - - - +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/index.html b/public/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/index.html index 36f25e35..7b591be5 100644 --- a/public/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/index.html +++ b/public/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/index.html @@ -1,115 +1,85 @@ + - - - - - - - + + + Script to Move All Disabled AD Objects to a Specified OU · GeekyRyan + + - + -Script to Move All Disabled AD Objects to a Specified OU - GeekyRyan - - + + + - - - - - - - + + + + + + + + + + + + + + + - + - - - - - + + + - - - - - - - - - - + + + - - - - - + - + + + - - - - - - - - - - - - + + + + + - - - - - - - - - + + @@ -119,354 +89,203 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - -
    -
    - - - -
    -
    -
    -

    Script to Move All Disabled AD Objects to a Specified OU

    - - -
    -
    -
    -

    The title says it all. This script will move all disabled AD objects to a specified OU. This script accepts parameters that will allow you to specify whether you want to move Users or Computers and the destination OU. It also accepts a “test mode” parameter that will run the script and output the results, without actually modifying Active Directory.

    -

    This is revision 1 of the script. There are still several improvements I would like to make, including better error handling and recovery.

    -

    If you have any suggestions or requests, please leave a comment.

    -

    Download Here

    - -
    - - - - - - +
    - - - - - - + - - - - - - +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/index.html b/public/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/index.html index 0a95c23e..01328ae7 100644 --- a/public/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/index.html +++ b/public/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/index.html @@ -1,483 +1,300 @@ + - - - - - - - + + + WDS Service: The Service did not respond in a timely fashion · GeekyRyan + + - + -WDS Service: The Service did not respond in a timely fashion - GeekyRyan + + + + + + + - - - - - - - - + + + + + + + + + + + - + + + + - - - - - + + + - - - + - + + + - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    WDS Service: The Service did not respond in a timely fashion

    - - -
    -
    -
    -

    This was a new one for me. Usually WDS is rock solid and it just works.

    +

    This was a new one for me. Usually WDS is rock solid and it just works.

    Anyway, I was getting ready to deploy some servers in my lab and found that I couldn’t get WDS to start on my deployment server. I got this error message when trying to start the service:

    -

    +

    I then tried to start the service from the Services console and got this error message:

    -

    +

    “This was just working yesterday”, I said to myself. What could possibly have happened since yesterday evening that could cause this? I looked in the event log and after scrolling through the Administrative Events, I found this:

    -

    +

    The solution was so obvious it was staring me in the face, but I wanted to verify first. So I fired up a cmd prompt and ran netstat, and found this:

    -

    +

    I had installed DHCP on this server the night before and totally forgot about it. Anyway, the solution was simple. I just needed to tell the WDS service to not listen on port 67. To do that, just open the WDS server properties and got to the “DHCP” tab. Then check the box next to “Do not listen on DHCP Ports”.

    -

    +

    I was then able to start the DHCP service.

    -
    - - - + - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/index.html b/public/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/index.html index bb747902..d0d6d6d9 100644 --- a/public/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/index.html +++ b/public/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/index.html @@ -1,480 +1,297 @@ + - - - - - - - + + + WSUS: An error occurred trying to connect the WSUS server · GeekyRyan + + - + -WSUS: An error occurred trying to connect the WSUS server - GeekyRyan + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + - - - - - - - - - + - + + + - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    WSUS: An error occurred trying to connect the WSUS server

    - - -
    -
    -
    -

    Ran into this error message when configuring a new WSUS server:

    -

    +

    Ran into this error message when configuring a new WSUS server:

    +

    Restarted the WSUS, WID, and IIS services to no avail. I even rebooted the server. The WSUS console would work for a short period of time, and then would randomly stop working.

    I found that the WSUS app pool in IIS was being disabled anytime new clients connected to the server. I believe this was because the app pool was running out of usable memory.

    -

    +

    You can manually start the app pool in IIS, but it will continue to crash.

    -

    +

    The solution for me was to increase the memory limit available for the application pool:

    -

    +

    By default it is only configured to use just under 2 GBs. I reconfigured it to use up to 4 GB and the WSUS console has not crashed since. After re-configuring the memory for the application pool, run an IIS reset or reboot the server.

    -

    +

    UPDATE: Setting the Private Memory Limit to “0” will allow the application pool to use whatever amount of memory it needs.

    -
    - - - + - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2016-11-18-wsus-update-files-not-downloading/index.html b/public/posts/2016-11-18-wsus-update-files-not-downloading/index.html index 9db74ac5..e5f82b95 100644 --- a/public/posts/2016-11-18-wsus-update-files-not-downloading/index.html +++ b/public/posts/2016-11-18-wsus-update-files-not-downloading/index.html @@ -1,479 +1,296 @@ + - - - - - - - + + + WSUS: Update Files Not Downloading (Content File Download Failed) · GeekyRyan + + - + -WSUS: Update Files Not Downloading (Content File Download Failed) - GeekyRyan + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + - - - - - - - - - + - + + + - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    WSUS: Update Files Not Downloading (Content File Download Failed)

    - - -
    -
    -
    -

    This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates:

    -

    +

    This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates:

    +

    You may also see this event (or similar) in the Event Log.

    -

    +

    This problem is caused by not specifying a valid path when assigning the WSUS content drive when first installing the role. The first time you load the WSUS console after installing the role, you will be prompted to specify the path to store Windows Update files. WSUS does not like to have its content directory be the root of a partition. For example, if I were to specify “e:” as the path for the Windows Update content, the wizard would give you an error message stating that the path is not valid. However, it doesn’t prompt you to re-enter the path if you click close. The WSUS console opens immediately after and that invalid path is where WSUS will try to store your update files. This is and has been a known bug for a while and needs to be addressed by Microsoft. Evidence of the invalid path can be found in the registry under:

    HKLMSoftwareMicrosoftUpdate ServicesServerSetupContentDir

    -

    +

    If you come across this problem, you can change the ContentDir above to a valid path. Keep in mind that it cannot be the root of a partition. You need to specify a drive letter with a subfolder (eg: e:wsus).

    -

    +

    The other option is to reinstall the WSUS role. If you remove the role, the WID database is not removed, unless you remove that role as well (or manually delete the database). This means that when you reinstall the WSUS role, it will be able to use that same database and any clients that have contacted the WSUS server will immediately show up in the console. The same is true for update metadata. The new WSUS installation will still have the same approvals, denials, etc. as the old installation.

    Regardless of what option you choose, I suggest rebooting the server after you make the changes.

    -
    - - - + - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/index.html b/public/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/index.html index b6579312..da680af7 100644 --- a/public/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/index.html +++ b/public/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/index.html @@ -1,471 +1,301 @@ + - - - - - - - + + + Running vSphere in VMware Workstation 12 · GeekyRyan + + - - -Running vSphere in VMware Workstation 12 - GeekyRyan - - - - - - + - - - - - - + + + - + + + + + + + + + + + + + - - - - - - - - + + + + - + + + - + - - - + + - - - + + + + - - - - - - + + + + - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Running vSphere in VMware Workstation 12

    - - -
    -
    -
    -

    In this post I’ll be walking through how to run a vSphere lab in VMware Workstation. I recently decided to obtain VCP6-DCV. Rather than driving up my electric bill like I’ve done in the past using physical servers, I’m attempting to run the entire lab on my workstation and a Synology NAS.

    +

    In this post I’ll be walking through how to run a vSphere lab in VMware Workstation. I recently decided to obtain VCP6-DCV. Rather than driving up my electric bill like I’ve done in the past using physical servers, I’m attempting to run the entire lab on my workstation and a Synology NAS.

    If you’ve ever installed ESXi, installing it in Workstation will be a familiar process for you. VMware tools is included in the installation disc, which makes installing ESXi in Workstation dramatically easier than it used to be. . The process is very simple, so I won’t be going through those steps here unless someone asks me to in the comments. I also will not be going through the process of installing Windows Server or configuring a domain controller/DNS/DHCP, as I am sure you have done so in the past if you are reading this.

    So that really only leaves us with installing vCenter. Most of the blogs I found for installing vCenter in VMware Workstation 12 were not accurate, and often left me with a broken installation. The process is somewhat straight-forward when deploying from the OVA. Let’s get started.

    -

    First, download the OVA for vCenter here: Download vCenter

    +

    First, download the OVA for vCenter here: Download vCenter

    Once the download has completed, click File > Open in Workstation. Browse to the OVA, then give your new VM a name and location if necessary. Accept the EULA when prompted.

    Be sure to read it! 😎

    Once the OVA finishes importing, do not power on the VM! There is some customization we need to do first. Close Workstation if it is open. Browse to the location on your PC that you imported the VM to. I’m using a Windows OS, so I will use File Explorer. Open the .VMX file (use Notepad or another text editor):

    -

    +

    This is the configuration file for your virtual machine. We can use it to customize the name, IPv4/6 details, DNS domain, etc. Scroll down to the last line of text, and paste this in:

    -
    guestinfo.cis.vmdir.password = “vmware!”
    -guestinfo.cis.appliance.net.addr.family = “ipv4”
    -guestinfo.cis.appliance.net.addr = “10.0.0.15”
    -guestinfo.cis.appliance.net.prefix = “24”
    -guestinfo.cis.appliance.net.mode = “static”
    -guestinfo.cis.appliance.net.dns.servers = “10.0.0.10”
    -guestinfo.cis.appliance.net.gateway = “10.0.0.1”
    -guestinfo.cis.appliance.root.passwd = “vmware!”
    +
    guestinfo.cis.vmdir.password = “vmware!”
    +guestinfo.cis.appliance.net.addr.family = “ipv4”
    +guestinfo.cis.appliance.net.addr = “10.0.0.15”
    +guestinfo.cis.appliance.net.prefix = “24”
    +guestinfo.cis.appliance.net.mode = “static”
    +guestinfo.cis.appliance.net.dns.servers = “10.0.0.10”
    +guestinfo.cis.appliance.net.gateway = “10.0.0.1”
    +guestinfo.cis.appliance.root.passwd = “vmware!”
     

    Customize the above code to your needs. You will likely need to change the IPv4 details. Save the .VMX file and close your text editor. Now you can power on the virtual machine, and vCenter will run through the installation process. The installation can take around 10-15 minute in my experience. You may see generic login screens during the installation of Photon, do not login or interrupt the installation. Once it is complete, you should see the DCUI below:

    -

    +

    You should now be able to browse to the IP address or DNS name of your vCenter server. Once you complete the configuration, you can login and see the page below: -

    +

    In my lab I am running 3 ESXi hosts, 1 Windows Server, and one vCenter server. Plenty to study for the VCP lab.

    -

    +

    Good luck and be sure to leave a comment if you have any questions!

    -
    - +
    - - - - -
    - - - - - - - + + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/index.html b/public/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/index.html index e98f50f7..0a054fda 100644 --- a/public/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/index.html +++ b/public/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/index.html @@ -1,118 +1,87 @@ + - - - - - - - + + + Access is Denied When Attempting to Delete a Dynamic Distribution Group · GeekyRyan + + - + -Access is Denied When Attempting to Delete a Dynamic Distribution Group - GeekyRyan + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - + + + - - - - - + - + + + - - - - - - - - - - - - + + + + + - - - - - - - - - + + @@ -122,352 +91,200 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - -
    -
    - - - -
    -
    -
    -

    Access is Denied When Attempting to Delete a Dynamic Distribution Group

    - - -
    -
    -
    -

    You may receive the error below when attempting to delete a dynamic distribution group.

    -

    -

    To resolve this, open ADUC and show advanced features (Click View > Advanced Features). Then find the object for the dynamic distribution group and open the properties window. Browse to the “Object” tab and uncheck the “Protect object from accidental deletion” box. Wait for ADDS to replicate or force replication yourself.

    -

    -

    Go back to the ECP and you should be able to delete the group.

    - -
    - - - - - - +
    - - - - - - + - - - - - - +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/posts/2017-06-20-how-to-permanently-remove-office-365-users/index.html b/public/posts/2017-06-20-how-to-permanently-remove-office-365-users/index.html index 429ff440..20966718 100644 --- a/public/posts/2017-06-20-how-to-permanently-remove-office-365-users/index.html +++ b/public/posts/2017-06-20-how-to-permanently-remove-office-365-users/index.html @@ -1,474 +1,291 @@ + - - - - - - - + + + How to Permanently Remove Office 365 Users · GeekyRyan + + - - -How to Permanently Remove Office 365 Users - GeekyRyan - - - - - - + - - - - - - + + + - + + + + + + + + + + + + + + - - - - - - - - + + + + - + + + - + - - - + + - - - + + + + - - - - - - + + + + - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    How to Permanently Remove Office 365 Users

    - - -
    -
    -
    -

    After deleting a user in Office 365, their account is moved to a ‘recycle bin’ for 30 days. This allows the user account to be easily recovered. This can often cause issues when attempting to recreate a mailbox while a hybrid configuration is in place.

    +

    After deleting a user in Office 365, their account is moved to a ‘recycle bin’ for 30 days. This allows the user account to be easily recovered. This can often cause issues when attempting to recreate a mailbox while a hybrid configuration is in place.

    To permanently delete the user within Office 365, first delete the user in the Office 365 Admin Portal or using Powershell. Then, connect to your Azure Active Directory environment with Powershell using the “Connect-MsolService” cmdlet.

    -

    +

    To see a list of user accounts currently in the recycle bin, run this cmdlet:

    -

    +

    Then, to permanently delete all accounts in the recycle bin, run this cmdlet:

    -

    +

    To remove a specific user, run this cmdlet:

    -

    +

    -
    - + - - - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2017-06-22-windows-8-file-history-windows-8-file-history/index.html b/public/posts/2017-06-22-windows-8-file-history-windows-8-file-history/index.html index 47444820..3d816dbd 100644 --- a/public/posts/2017-06-22-windows-8-file-history-windows-8-file-history/index.html +++ b/public/posts/2017-06-22-windows-8-file-history-windows-8-file-history/index.html @@ -1,112 +1,81 @@ + - - - - - - - + + + Windows 8 File History · GeekyRyan + + - - -Windows 8 File History - GeekyRyan - - - - - - - - - + - - - + + + - + + + + + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - - + + + + + + + - - - - - - - - - @@ -115,337 +84,198 @@ - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Windows 8 File History

    - - -
    -
    -
    -

    File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. To begin using it, connect an external drive and search for File History on the Start Screen:

    -

    +

    File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. To begin using it, connect an external drive and search for File History on the Start Screen:

    +

    After opening File History, you will see this screen:

    -

    +

    To enable File History, click the ‘Turn On’ button. You can select the drive you want to use by clicking ‘Select Drive’ on the left hand side from this same screen. The first time you enable File History, it will create a full backup of all files on your computer, except for files that you do not access (system files), and files you have chosen to exclude. From then on, it will create a versioned copy of every file that has changed since the last backup.

    You can use a locally attached drive or a network share for File History. To choose how often File History backs up files; choose ‘Advanced Settings’. From here you can also choose how much space on the drive is used, and how long saved versions of files should be kept.

    When the total space allocated to File History has been used, the feature will delete the oldest versions of files to make room for newer versions.

    -
    - + - - - - -
    - - - - - - - + + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/index.html b/public/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/index.html index 1bcc9806..58b74580 100644 --- a/public/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/index.html +++ b/public/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/index.html @@ -1,118 +1,88 @@ + - - - - - - - + + + New Script: BulkAdd-SpamFilterWhitelist.ps1 · GeekyRyan + + - + -New Script: BulkAdd-SpamFilterWhitelist.ps1 - GeekyRyan + + + + + + + - - - - - - - - - + + + + + + + + + + + + - + + + + - - - - - - - - - - - - - - - - + + + - - - - - + - + + + - - - - - - - - - - - - + + + + + - - - - - - - - - + + @@ -122,353 +92,202 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - -
    -
    - - - - - - - - - - + - - - - - - +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/posts/2017-06-27-migrate-windows-deployment-services-to-new-server/index.html b/public/posts/2017-06-27-migrate-windows-deployment-services-to-new-server/index.html index 1fc3eefc..1d7f5777 100644 --- a/public/posts/2017-06-27-migrate-windows-deployment-services-to-new-server/index.html +++ b/public/posts/2017-06-27-migrate-windows-deployment-services-to-new-server/index.html @@ -1,115 +1,82 @@ + - - - - - - - + + + Migrate Windows Deployment Services to New Server · GeekyRyan + + - - -Migrate Windows Deployment Services to New Server - GeekyRyan - - - - - - + - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - + + + + - - + + + - - - - - + - + + + - - - - - - - - - - - - + + + + + - - - - - - - - - + + @@ -119,116 +86,104 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - - -
    -
    - + + + -
    -
    -
    -

    Migrate Windows Deployment Services to New Server

    - -
    +
    + +
    +
    +
    +
    +

    + + Migrate Windows Deployment Services to New Server + +

    +
    + -
    -

    We have been making a great effort to move all of our internal services to Windows Server 2016. This past week, it was WDS’ turn to get migrated. Migrating this role is extremely simple. Here are the steps that I took:

    +
    + +
    + +

    We have been making a great effort to move all of our internal services to Windows Server 2016. This past week, it was WDS’ turn to get migrated. Migrating this role is extremely simple. Here are the steps that I took:

    1. Create new server and install WDS role.
    2. Stop WDS Service on old server
    3. Stop WDS Service on new server
    4. -
    5. Use my “Copy-Files” PowerShell script (Available Here: Copy-Files.ps1) to copy RemoteInstall Share to new server
    6. +
    7. Use my “Copy-Files” PowerShell script (Available Here: Copy-Files.ps1) to copy RemoteInstall Share to new server
    8. Start WDS Service on new Server
    9. Shutdown old WDS Server completely
    10. Update option 66/67 in DHCP scopes to reflect new WDS Server
    11. @@ -238,217 +193,93 @@

      Migrate Windows Deployment Services to New Server<

      If you are unable to start the WDS service, delete the WDS database and logs from the old server located at <drive letter>:RemoteInstallStoresMetadata*.*. You should be able to start the service after deleting these files.

      Simple enough! 🙂

      -

    - +
    - - - -
    - - - - - - + + + + + + + + +
    +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    + + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/index.html b/public/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/index.html index 443eac15..c5a6fd9d 100644 --- a/public/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/index.html +++ b/public/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/index.html @@ -1,112 +1,82 @@ + - - - - - - - + + + Exchange 2016 Hybrid Deploy Check: Username or Password Invalid · GeekyRyan + + - - -Exchange 2016 Hybrid Deploy Check: Username or Password Invalid - GeekyRyan - - - - - - - - - + - - - + + + - + + + + + + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - - + + + + + + + - - - - - - - - - @@ -115,354 +85,201 @@ - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Exchange 2016 Hybrid Deploy Check: Username or Password Invalid

    - - -
    -
    -
    -

    These days, it seems every Microsoft product comes with its own unique set of head scratchers. Microsoft Exchange Server is no exception to this. I was installing Exchange 2016 earlier today, to be used as a hybrid configuration server for Office 365 (no local mailboxes). I downloaded the self depackaging executable from Microsoft, and attempted to install it. If you currently have a hybrid configuration (which we did, with Exchange 2010), the Exchange 2016 installer will detect this and run some tests to verify that the Office 365 tenant is ready for Exchange 2016 (more info here: https://technet.microsoft.com/en-us/library/ms.exch.setup.hybridconfigurationstatuspage(v=exchg.160).aspx). You’ll be prompted for Office 365 credentials (the user must have the Organization Management role). Seems simple enough, right? Wrong.

    +

    These days, it seems every Microsoft product comes with its own unique set of head scratchers. Microsoft Exchange Server is no exception to this. I was installing Exchange 2016 earlier today, to be used as a hybrid configuration server for Office 365 (no local mailboxes). I downloaded the self depackaging executable from Microsoft, and attempted to install it. If you currently have a hybrid configuration (which we did, with Exchange 2010), the Exchange 2016 installer will detect this and run some tests to verify that the Office 365 tenant is ready for Exchange 2016 (more info here: https://technet.microsoft.com/en-us/library/ms.exch.setup.hybridconfigurationstatuspage(v=exchg.160).aspx). You’ll be prompted for Office 365 credentials (the user must have the Organization Management role). Seems simple enough, right? Wrong.

    After typing in the username and pasting the password into the password field, setup came back with an error message stating the username or password was wrong. I then clicked the back button, and it crashed. I ran through this process a few more times, all with the same outcome. I even rebooted the server, which (in my opinion) should never be the resolution to a software problem. I looked through setup logs and found no indication of what the problem could be…

    -

    +

    It was on the fourth try that I typed in the password, and this seemed to work. I didn’t receive any error messages about the credentials being wrong. The Exchange setup seemed to continue on successfully. However, it then failed with a different error:

    -

    +

    I again looked through the setup logs and found that this error happened anytime setup tried to run the “Get-OrganizationConfig” cmdlet. After troubleshooting for a little while, and no resolution in sight, I turned to Google. One of the posts I came across said that this is a bug in the Exchange installer, and to try and use the Cumulative Update installer instead. Apparently, with Exchange 2016, the Cumulative Update installer’s include all of the Exchange binaries, not just the updated binaries. I downloaded the installer for CU7 (all 6 gigabytes of it…) and successfully installed Exchange 2016. Hope this helps anyone out there struggling with this.

    -
    - - - - + - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2017-11-08-remove-stubborn-psc-or-vcenter/index.html b/public/posts/2017-11-08-remove-stubborn-psc-or-vcenter/index.html index 686ae050..88509d82 100644 --- a/public/posts/2017-11-08-remove-stubborn-psc-or-vcenter/index.html +++ b/public/posts/2017-11-08-remove-stubborn-psc-or-vcenter/index.html @@ -1,112 +1,81 @@ + - - - - - - - + + + Remove Stubborn PSC or vCenter Appliance from an SSO Domain · GeekyRyan + + - - -Remove Stubborn PSC or vCenter Appliance from an SSO Domain - GeekyRyan - - - - - - - - - + - - - + + + - + + + + + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - - + + + + + + + - - - - - - - - - @@ -115,353 +84,207 @@ - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Remove Stubborn PSC or vCenter Appliance from an SSO Domain

    - - -
    -
    -
    -

    While attempting to decommission one of our vCenter sites, I ran into an issue removing one of the PSCs. This site consisted of two PSCs and one vCenter appliance. I removed the first PSC from the SSO domain successfully, and then removed the vCenter appliance. Things became a little tricky during the removal of the final PSC. This PSC did not get removed even after running the cmsso-util command. This article will detail the steps I took in decommissioning the site, as well as removing the stubborn PSC.

    -

    First, we need to check if vCenter is currently using the PSC we plan on decommissioning. If it is, we need to use the cmsso-util command to redirect vCenter to a different PSC. Instructions for redirecting vCenter can be found here: https://kb.vmware.com/s/article/2113917?language=en_US

    +

    While attempting to decommission one of our vCenter sites, I ran into an issue removing one of the PSCs. This site consisted of two PSCs and one vCenter appliance. I removed the first PSC from the SSO domain successfully, and then removed the vCenter appliance. Things became a little tricky during the removal of the final PSC. This PSC did not get removed even after running the cmsso-util command. This article will detail the steps I took in decommissioning the site, as well as removing the stubborn PSC.

    +

    First, we need to check if vCenter is currently using the PSC we plan on decommissioning. If it is, we need to use the cmsso-util command to redirect vCenter to a different PSC. Instructions for redirecting vCenter can be found here: https://kb.vmware.com/s/article/2113917?language=en_US

    To check what PSC your vCSA is currently pointing to, browse to the Advanced Settings for the vCSA in the vSphere Web Client. Filter by this key: config.vpxd.sso.admin.uri

    To remove a PSC or vCSA from an SSO domain, connect to a PSC via SSH and run these commands:

    To remove a PSC from the vSphere SSO domain:

    -
    cmsso-util unregister –node-pnid psc01.ad.vcplab.local –username administrator@your\_domain\_name –passwd vCenter\_Single\_Sign\_On\_password
    +
    cmsso-util unregister –node-pnid psc01.ad.vcplab.local –username administrator@your\_domain\_name –passwd vCenter\_Single\_Sign\_On\_password
     

    To remove a vCSA from the vSphere SSO domain:

    -
    cmsso-util unregister –node-pnid vcsa.ad.vcplab.local –username administrator@your\_domain\_name –passwd vCenter\_Single\_Sign\_On\_password
    +
    cmsso-util unregister –node-pnid vcsa.ad.vcplab.local –username administrator@your\_domain\_name –passwd vCenter\_Single\_Sign\_On\_password
     

    After running these commands, delete the virtual appliances. You can also verify the appliances have been removed by browsing to Administration > System Configuration > Nodes in the vSphere Web Client.

    If cmsso-util fails to remove any of the nodes, you can use this command to force the removal:

    -
    vdcleavefed -h vcsa.ad.vcplab.local -u Administrator -w Passw0rd!
    +
    vdcleavefed -h vcsa.ad.vcplab.local -u Administrator -w Passw0rd!
     

    Upon successful completion, you should see something like this:

    -
    /usr/lib/vmware-vmdir/bin/vdcleavefed -h vcsa.ad.vcplab.local -u administrator* password:
    -vdcleavefd offline for server vcsa.ad.vcplab.local
    -Leave federation cleanup done
    -

    When specifying the username, use the SSO admin (administrator). However, do not use the full UPN (administrator@vsphere.local). Doing so will cause the command to fail.

    - -
    - - - +
    /usr/lib/vmware-vmdir/bin/vdcleavefed -h vcsa.ad.vcplab.local -u administrator* password:
    +vdcleavefd offline for server vcsa.ad.vcplab.local
    +Leave federation cleanup done
    +

    When specifying the username, use the SSO admin (administrator). However, do not use the full UPN (administrator@vsphere.local). Doing so will cause the command to fail.

    +
    - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2018-07-13-removing-forest-from-azure-ad-connect/index.html b/public/posts/2018-07-13-removing-forest-from-azure-ad-connect/index.html index 2b34404b..2c864d34 100644 --- a/public/posts/2018-07-13-removing-forest-from-azure-ad-connect/index.html +++ b/public/posts/2018-07-13-removing-forest-from-azure-ad-connect/index.html @@ -1,112 +1,83 @@ + - - - - - - - + + + Removing a Forest from Azure AD Connect · GeekyRyan + + - - -Removing a Forest from Azure AD Connect - GeekyRyan - - - - - - - - - + - - - + + + - + + + + + + + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - - + + + + + + + - - - - - - - - - @@ -115,125 +86,125 @@ - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Removing a Forest from Azure AD Connect

    - - -
    -
    -
    -

    In an organization with multiple Active Directory forests, you may want to sync objects from trusted forests. Adding trusted forests to Azure AD Sync is a simple process that I will likely cover in a future article. The focus of this post is the not-so-obvious process of removing a forest from Azure AD Connect. This can be a daunting and somewhat scary thing to do. Not fully understanding the process or having someone to guide you can leave you with thoughts like “what happens when I remove the forest from Azure AD Sync? Do on-premises objects get deleted? Are cloud objects deleted?”. I will try to answer these questions to the best of my ability and hopefully make the process simple and stress-free for you.

    +

    In an organization with multiple Active Directory forests, you may want to sync objects from trusted forests. Adding trusted forests to Azure AD Sync is a simple process that I will likely cover in a future article. The focus of this post is the not-so-obvious process of removing a forest from Azure AD Connect. This can be a daunting and somewhat scary thing to do. Not fully understanding the process or having someone to guide you can leave you with thoughts like “what happens when I remove the forest from Azure AD Sync? Do on-premises objects get deleted? Are cloud objects deleted?”. I will try to answer these questions to the best of my ability and hopefully make the process simple and stress-free for you.

    To get started, we first need to open PowerShell and disable the AD Sync scheduler. You can do this by running the “Set-ADSyncScheduler” cmdlet:

    -

    +

    This cmdlet is included in the ADSync PowerShell module. You may need to load the module prior to using the cmdlet:

    -
    Import-Module ADSync
    +
    Import-Module ADSync
     

    The next step is to open FIM (miisclient) located in the install directory of Microsoft Azure AD Sync. By default, this is C:Program FilesMicrosoft Azure AD SyncUIShellmiisclient.exe. Once you have FIM open, click on the Connectors tab, then right click on the connector for the forest that you want to delete, and click “Delete”.

    -

    +

    You will then be prompted, asking if you want to just delete the Connector Space, or delete the Connector and the Connector Space. The former open removes all data, but keeps the configuration in case you want to use it again later. The latter option deleted the data and the configuration. This open should only be used if you don’t plan on syncing the forest again.

    -

    +

    The connector for the forest is now deleted, but what actually happens? Your on-premises objects do not get removed for the forest, and cloud objects are removed. Simple enough, right?

    Now you just need to re-enable the AD Sync Scheduler with this cmdlet:

    -
    Set-ADSyncScheduler -SyncCycleEnabled $true
    +
    Set-ADSyncScheduler -SyncCycleEnabled $true
     

    One last thing to mention… You may receive an email from the Microsoft Online Services Team stating that the identity synchronization failed due to a deletion threshold being met. By default, Azure AD Connect will not allow you to delete more than 500 objects in your cloud directory. This is to protect you from making a careless (potentially resume generating) mistake. The email will look something like this:

    -

    +

    If you are certain that you want to proceed with deleting the objects, here are the steps:

    1. @@ -243,11 +214,11 @@

      Removing a Forest from Azure AD Connect

      Open FIM (miisclient), and click on the “Connectors” button at the top of the window. Right click on the connector of type “Windows Azure Active Directory”, and select “Run…”.

    -

    +

    1. Next, click Export and then click Ok.
    -

    +

    1. Allow the connector to run. This will take a few minutes. You can monitor the progress by clicking the Operations button.

      @@ -256,248 +227,96 @@

      Removing a Forest from Azure AD Connect

      Once this completes, you need to re-enable the deletion threshold. You can do this by running this cmdlet:

    -
    Enable-ADSyncExportDeletionThreshold -DeletionThreshold 500.
    +
    Enable-ADSyncExportDeletionThreshold -DeletionThreshold 500.
     

    You will be prompted for credentials again. Just type in your Azure AD Global Admin creds. You can even lower the threshold if you’d like. I set mine to 100.

    -
    - - - - +
    - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2018-07-18-azure-ad-connect-health-latest-data-is/index.html b/public/posts/2018-07-18-azure-ad-connect-health-latest-data-is/index.html index 362e006b..6b54a67d 100644 --- a/public/posts/2018-07-18-azure-ad-connect-health-latest-data-is/index.html +++ b/public/posts/2018-07-18-azure-ad-connect-health-latest-data-is/index.html @@ -1,481 +1,300 @@ + - - - - - - - + + + Azure AD Connect Health: Latest Data is not Available in Azure Portal · GeekyRyan + + - - -Azure AD Connect Health: Latest Data is not Available in Azure Portal - GeekyRyan - - - - - - + - - - - - - + + + - + + + + + + + + + + + + + + + - - - - - - - - + + + + - + + + - + - - - + + - - - + + + + - - - - - - + + + + - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Azure AD Connect Health: Latest Data is not Available in Azure Portal

    - - -
    -
    -
    -

    I recently had to create a new Azure AD Connect server, and found that it was not able to report health status in the Azure Portal. After some troubleshooting/research, I was able to get the health status report working by registering the health agent on the server with Azure AD Health Services. Doing this involves running one PowerShell cmdlet on your AD Connect server and providing global administrator credentials.

    -

    +

    I recently had to create a new Azure AD Connect server, and found that it was not able to report health status in the Azure Portal. After some troubleshooting/research, I was able to get the health status report working by registering the health agent on the server with Azure AD Health Services. Doing this involves running one PowerShell cmdlet on your AD Connect server and providing global administrator credentials.

    +

    First, let’s test the status of the agent communication:

    -

    +

    If you do not receive any errors, that means the Azure AD Connect Health agent on your server is able to successfully communicate with the cloud service. Now, let’s register the agent:

    -

    +

    You will be prompted for credentials. The credentials you provide need to be a global administrator account in your Azure AD tenant.

    -

    +

    You should receive some output stating that the registration is successful (or it failed).

    -

    +

    Now, just go back to the Azure Portal and refresh the page. The message stating that the “latest data is not available” should be gone.

    -

    +

    -
    - + - - - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2018-07-26-azure-ad-connect-no-start-connection/index.html b/public/posts/2018-07-26-azure-ad-connect-no-start-connection/index.html index b32befc6..19ad00d2 100644 --- a/public/posts/2018-07-26-azure-ad-connect-no-start-connection/index.html +++ b/public/posts/2018-07-26-azure-ad-connect-no-start-connection/index.html @@ -1,480 +1,303 @@ + - - - - - - - + + + Azure AD Connect No-Start-Connection · GeekyRyan + + - - -Azure AD Connect No-Start-Connection - GeekyRyan - - - - - - + - - - - - - + + + - + + + + + + + + + + + + + + + + + - - - - - - - - + + + + - + + + - + - - - + + - - - + + + + - - - - - - + + + + - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Azure AD Connect No-Start-Connection

    - - -
    -
    -
    -

    This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working.

    +

    This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working.

    After forcing the sync, I opened miisclient and noticed some strange errors. We sync multiple on-prem AD forests to Azure AD, and the status for one of them was “no-start-connection”. That error in itself does not seem significant to me. However, after clicking on the “failed-connection” link in the Connection Status pane, things became much more clear.

    -

    -

    +

    +

    The domain controllers for the forest in question are in a datacenter that is geographically separated from the datacenter that our Azure AD Sync server lives in. The two sites are connected via a S2S VPN.

    There was obviously some type of connection issue between our two datacenters. In my case, the issue was transient, and resolved itself after a few minutes. But if you’re experiencing this error message, check your L2/L3 connection. Also, verify DNS is working and someone didn’t make changes to your firewall(s). Just walk up or down the OSI model and you’ll eventually find the problem.

    -
    - + - - - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2018-08-21-active-directory-migration-toolkit-rpc/index.html b/public/posts/2018-08-21-active-directory-migration-toolkit-rpc/index.html index e1bec72b..d565c38e 100644 --- a/public/posts/2018-08-21-active-directory-migration-toolkit-rpc/index.html +++ b/public/posts/2018-08-21-active-directory-migration-toolkit-rpc/index.html @@ -1,118 +1,86 @@ + - - - - - - - + + + Active Directory Migration Toolkit &#8211; The RPC Server is Unavailable (hr=0x800706ba) · GeekyRyan + + - + -Active Directory Migration Toolkit &#8211; The RPC Server is Unavailable (hr=0x800706ba) - GeekyRyan + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - + + + - - - - - + - + + + - - - - - - - - - - - - + + + + + - - - - - - - - - + + @@ -122,349 +90,196 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - -
    -
    - - - -
    -
    -
    -

    Active Directory Migration Toolkit &#8211; The RPC Server is Unavailable (hr=0x800706ba)

    - - -
    -
    -
    -

    When migrating computer objects using the Active Directory Migration Tool, you may encounter the following error:

    -

    -

    In addition, the Migration Log may show the following error:

    -

    -

    This is typically caused by a host-side firewall. To resolve this, deploy a GPO to disable the Windows firewall prior to migrating the computer account. I like to create a special OU for computers (I typically name it “PreMigration”) that I will move computer objects to prior to migrating them. This OU will have two policies applied. One to disable the Windows Firewall and another to start the Remote Registry service. Both are required for the computer object to successfully migrate.

    - -
    - - - - - - +
    - - - - - - + - - - - - - +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/posts/2018-08-21-azure-site-recovery-vmware-to-azure/index.html b/public/posts/2018-08-21-azure-site-recovery-vmware-to-azure/index.html index 3fd4a12c..e6cf2175 100644 --- a/public/posts/2018-08-21-azure-site-recovery-vmware-to-azure/index.html +++ b/public/posts/2018-08-21-azure-site-recovery-vmware-to-azure/index.html @@ -1,476 +1,293 @@ + - - - - - - - + + + Azure Site Recovery &#8211; VMware-to-Azure: Wrong IP address discovered for VM · GeekyRyan + + - + -Azure Site Recovery &#8211; VMware-to-Azure: Wrong IP address discovered for VM - GeekyRyan + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + - - - - - - - - - + - + + + - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Azure Site Recovery &#8211; VMware-to-Azure: Wrong IP address discovered for VM

    - - -
    -
    -
    -

    When replicating virtual machines from VMware to Azure using Site Recovery, you may encounter an issue where the Configuration server discovers the wrong IP address for a VM. This can be caused by stale entries within the infrastructurevms MySQL table that is used by ASR to track VM attributes.

    +

    When replicating virtual machines from VMware to Azure using Site Recovery, you may encounter an issue where the Configuration server discovers the wrong IP address for a VM. This can be caused by stale entries within the infrastructurevms MySQL table that is used by ASR to track VM attributes.

    To resolve this issue, you first need to disable replication for the VM in the Azure Portal.

    -

    +

    Next, login to your ASR Configuration Server and open a CMD prompt as administrator. Browse to the bin directory for your ASR installation. For example, in my case ASR is installed on the E: partition under the following directory:

    E:\Program Files (x86)Microsoft Azure Site Recoveryhomesvsystemsbin

    Type in this command to remove the VM from the ASR database (replace IP address with the IP of your VM):

    -
    perl Unregister-ASRComponent.pl -IPAddress 10.0.0.4 -Component Source
    +
    perl Unregister-ASRComponent.pl -IPAddress 10.0.0.4 -Component Source
     

    That’s it. You should now be able to reconfigure replication for the VM, and ASR will discover the correct info about the VM.

    -
    - - - +
    - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2019-01-14-error-when-reinstalling-dirsync/index.html b/public/posts/2019-01-14-error-when-reinstalling-dirsync/index.html index 4ce1c747..0aed992a 100644 --- a/public/posts/2019-01-14-error-when-reinstalling-dirsync/index.html +++ b/public/posts/2019-01-14-error-when-reinstalling-dirsync/index.html @@ -1,115 +1,82 @@ + - - - - - - - + + + Error When Reinstalling DirSync · GeekyRyan + + - - -Error When Reinstalling DirSync - GeekyRyan - - - - - - + - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - + + + + - - + + + - - - - - + - + + + - - - - - - - - - - - - + + + + + - - - - - - - - - + + @@ -119,330 +86,198 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - - -
    -
    - + + + -
    -
    -
    -

    Error When Reinstalling DirSync

    - -
    +
    + +
    +
    +
    +
    +

    + + Error When Reinstalling DirSync + +

    +
    + -
    -

    Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process:

    -

    +
    + +
    + +

    Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process:

    +

    I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do:

    • Uninstall Windows Azure Active Directory Sync tool and reboot

    -

    +

    • Remove this directory and all subfolders: C:\Program Files\Windows\Azure Active Directory Sync

    -

    +

    • If you created a domain account to use for DirSync, remove it. Also remove the Office 365 account you created. • Delete the Group accounts that the DirSync wizard created. Their names all begin with “FIM”

    -

    +

    • Uninstall MSSQL • Delete the MSSQL directory: C:Program FilesMicrosoft SQL Server • Reboot! • You should be able to install and configure DirSync now.

    -

    +

    -
    - +
    - - - -
    - - - - - - + + + + + + + + +
    +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    + + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2020-10-07-cisco-anyconnect-vpn-establishment/index.html b/public/posts/2020-10-07-cisco-anyconnect-vpn-establishment/index.html index 889b4d0c..4d4ec1a3 100644 --- a/public/posts/2020-10-07-cisco-anyconnect-vpn-establishment/index.html +++ b/public/posts/2020-10-07-cisco-anyconnect-vpn-establishment/index.html @@ -1,482 +1,303 @@ + - - - - - - - + + + Cisco AnyConnect &#8211; VPN Establishment Capability from a Remote Desktop is Disabled · GeekyRyan + + - + -Cisco AnyConnect &#8211; VPN Establishment Capability from a Remote Desktop is Disabled - GeekyRyan + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + - - - - - - - - - + - + + + - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Cisco AnyConnect &#8211; VPN Establishment Capability from a Remote Desktop is Disabled

    - - -
    -
    -
    -

    I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution.

    -

    +

    I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution.

    +

    Upon installation, AnyConnect pulls down a profile from the ASA containing several settings. This profile is in xml format and is located (on a Windows machine) at %programdata%CiscoCisco AnyConnect Secure Mobility ClientProfileAnyConnectProfile.xsd.

    To resolve this issue and connect to your VPN, open this file with notepad (or any text editor, run as admin), search for the “WindowsVPNEstablishment” tag, and modify the value. The default value is “LocalUsersOnly”, you will need to change it to “AllowRemoteUsers”. Save and close the file, then restart the machine.

    BEFORE:

    -

    +

    AFTER:

    -

    +

    -
    - - - + - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2020-10-28-could-not-connect-to-vmware-directory/index.html b/public/posts/2020-10-28-could-not-connect-to-vmware-directory/index.html index bfe527c9..3f7d2090 100644 --- a/public/posts/2020-10-28-could-not-connect-to-vmware-directory/index.html +++ b/public/posts/2020-10-28-could-not-connect-to-vmware-directory/index.html @@ -1,475 +1,294 @@ + - - - - - - - + + + Could not connect to VMware Directory Service via LDAP when Deploying New vCenter Appliance · GeekyRyan + + - + -Could not connect to VMware Directory Service via LDAP when Deploying New vCenter Appliance - GeekyRyan + + + + + + + - - - - - - - - + + + + + + + + + + - + + + + - - - - - + + + - - - + - + + + - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Could not connect to VMware Directory Service via LDAP when Deploying New vCenter Appliance

    - - -
    -
    -
    -

    Problem:

    +

    Problem:

    Deploying a brand new vCSA 6.7 appliance results in the following error during the second stage of the deployment.

    -

    +

    Solution:

    This problem is almost always caused by DNS resolution. Once you create the appropriate A and PTR record for your appliance on a LOCAL DNS server, you should be to successfully complete the deployment. Local DNS resolution is required, you cannot use a public DNS server while installing vCenter. For example, 8.8.8.8 will not work.

    Since you have already completed Stage 1 of the deployment, you can login to the appliance via SSH and update the DNS settings. This will only work if you chose to enable SSH during Stage 2 of the deployment.

    SSH to the appliance and run “/opt/vmware/share/vami/vami_config_net” (without quotes). Choose option 4 to update DNS settings and option 3 to update the hostname (if necessary). The deployment wizard states that a hostname is optional, but it is actually required. I have never had a successful deployment without specifying the hostname.

    -

    +

    You can then verify the DNS settings have been updated in the resolve.conf:

    -

    -

    - -
    - +

    +

    - + - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/index.html b/public/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/index.html index aff631b4..5f864ecb 100644 --- a/public/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/index.html +++ b/public/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/index.html @@ -1,251 +1,217 @@ + - - - - - - - + + + Deploy a New ADDS Forest on Server 2019 Core · GeekyRyan + + - + -Deploy a New ADDS Forest on Server 2019 Core - GeekyRyan + + + + + + + - - - - - - - - + + + + + + + + + + + - + + + + - - - - - + + + - - - + - + + + - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Deploy a New ADDS Forest on Server 2019 Core

    - - -
    -
    -
    -

    Prerequisites:

    +

    Prerequisites:

    Change server name and IP address Configure time settings and NTP

    In this post we will be reviewing the basic installation of the Active Directory Domain Services role and setup of a new forest on Windows Server Core 2019.

    To get started, login to your server with administrator privileges. You will first need to type in “powershell” in the cmd prompt to start powershell. Once you do that, type in the following command to install the Active Directory Domain Services role:

    -

    +

    After installing the role, we’ll continue by creating a new ADDS Forest and promoting this server to the primary domain controller.

    First, we’ll need to gather a password. This password will not be used for a domain user account. The local administrator on this server will become the domain administrator account for the domain. The password we’re gathering in the next step will be used for Directory Services Restore Mode (DSRM). DSRM is a recovery mode used to recover domain controllers that won’t boot up. We technically only need a password, not a username for this account.

    Type in the following:

    -
    $cred = Get-Credential
    +
    $cred = Get-Credential
     

    In the username field for the credentials prompt below, just type in anything you want, as the value will not be used. This prompt will store our username/password in a variable object. We can then access the password within the credential object by typing:

    -
    $cred.password
    +
    $cred.password
     

    We can see that this password is stored as a secure string object. Let’s continue on with the Directory Services installation.

    -

    -

    +

    +

    Once we have our credential variable, we can install a new forest and domain controller using the command below. Let us break down what this cmd is doing:

    -

    +

    Install-ADDSForest: The powershell cmdlet to create a new forest and domain controller

    -DomainName: The domain name to be used for the forest

    -DomainNetBiosName: The domain “Short name” to be used for the forest. This is the value used when you type in a username in the domainusername format. Example “myDomainbgates”.

    @@ -257,242 +223,93 @@

    Deploy a New ADDS Forest on Server 2019 Core

    -InstallDNS: Install the DNS role alongside the ADDS role.

    -WhatIf: This is a powershell “thing”. Most cmdlets have the “whatif” parameter. It basically allows you to run the cmdlet in “test” mode without actually making any changes to your environment. Once you’re happy with the output, you can remove the “whatif” parameter and run the command to install ADDS and promote this server to a domain controller.

    -
    - - - +
    - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/index.html b/public/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/index.html index e1de704d..a308cca7 100644 --- a/public/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/index.html +++ b/public/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/index.html @@ -1,492 +1,309 @@ + - - - - - - - + + + Reset GRUB/root Password for vCenter/PSC Appliance · GeekyRyan + + - - -Reset GRUB/root Password for vCenter/PSC Appliance - GeekyRyan - - - - - - + - - - - - - + + + - + + + + + + + + + + + + + + - - - - - - - - + + + + - + + + - + - - - + + - - - + + + + - - - - - - + + + + - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Reset GRUB/root Password for vCenter/PSC Appliance

    - - -
    -
    -
    -

    In Redhat/Fedora/Cent, GRUB can be protected by running the grub-md5-crypt command and pasting the outputted password hash into the grub.conf file. vSphere 6.0 password protects grub by default. If you change the root password in the VAMI, the GRUB password is changed to match. If you do not change the root password, the GRUB password is “vmware”.

    -

    To reset the GRUB password, we need to boot into a Cent or Redhat live CD. The ISO can be obtained here: https://www.centos.org/download/. Its best to upload the ISO to a datastore that the appliance has access to.

    +

    In Redhat/Fedora/Cent, GRUB can be protected by running the grub-md5-crypt command and pasting the outputted password hash into the grub.conf file. vSphere 6.0 password protects grub by default. If you change the root password in the VAMI, the GRUB password is changed to match. If you do not change the root password, the GRUB password is “vmware”.

    +

    To reset the GRUB password, we need to boot into a Cent or Redhat live CD. The ISO can be obtained here: https://www.centos.org/download/. Its best to upload the ISO to a datastore that the appliance has access to.

    Stop the appliance and attach the ISO:

    -

    +

    Be sure to select the “Connect at Power On” option. Boot the VM into the ISO and select the “Troubleshooting” option.

    -

    +

    Next, choose “Rescure a Red hat (or CentOS depending on your ISO) Enterprise Linux System”

    -

    +

    Select “Continue” to mount the VCSA 6.0’s root filesystem in Read/write mode under /mnt/sysimage. RHEL 7.2 is capable to detect the VCSA’s root volume and mounts it.

    -

    +

    The VCSA root filesystem is mounted under /mnt/sysimage and you can now access (and modify) it using the shell. Navigate to /mnt/sysimage/boot and list the contents. You’ll see we now have access to the grub directory:

    -

    +

    cd to the grub directory and list the contents. Look for a file called “menu.lst”. This file holds the grub boot loader password. Open this file with vi by typing “vi menu.lst”. Navigate to the line beginning with “password” using the arrow keys, and then type “dd” to remove the line.

    -

    +

    You can then save the file by pressing “:wq” (without quotes). You can now cat the file and see that the password has been removed.

    -

    +

    Exit the shell (this will reboot the server). Detach the ISO and boot the appliance. Once the system is booted, stop the VCSA in the GRUB menu (by pressing the escape key during boot) to break the OS root password.

    -

    +

    Press “e” to edit the boot commands for the kernel.

    -

    +

    Append “init=/bin/bash” to the line in this step and press enter.

    -

    +

    Press “b” to boot the system.

    -

    +

    You will now boot into a bash shell where you can set the root password.

    -

    +

    Once this is done, exit the shell by typing “exit”. You can now boot the appliance and login with your new root password.

    -
    - + - - - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2020-11-03-replicate-azure-vm-image-between-regions/index.html b/public/posts/2020-11-03-replicate-azure-vm-image-between-regions/index.html index 75d83530..b32b7971 100644 --- a/public/posts/2020-11-03-replicate-azure-vm-image-between-regions/index.html +++ b/public/posts/2020-11-03-replicate-azure-vm-image-between-regions/index.html @@ -1,112 +1,81 @@ + - - - - - - - + + + Replicate an Azure VM Image Between Regions · GeekyRyan + + - - -Replicate an Azure VM Image Between Regions - GeekyRyan - - - - - - - - - + - - - + + + - + + + + + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - - + + + + + + + - - - - - - - - - @@ -115,368 +84,214 @@ - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Replicate an Azure VM Image Between Regions

    - - -
    -
    -
    -

    Let’s say you have a VM in Azure North Central. You created this VM from a custom image that you maintain in an Azure image repository. Now, what if you wanted to create that same VM in Azure South Central, and use the same reference image? A standard image repository is limited to the region that it exists in. The answer here is to create a Shared Image Library, add the image to it, and then configure the image to replicate to other Azure regions.

    +

    Let’s say you have a VM in Azure North Central. You created this VM from a custom image that you maintain in an Azure image repository. Now, what if you wanted to create that same VM in Azure South Central, and use the same reference image? A standard image repository is limited to the region that it exists in. The answer here is to create a Shared Image Library, add the image to it, and then configure the image to replicate to other Azure regions.

    This article assumes you already have an image.

    -

    First, create a Shared Image Gallery in Azure. Browse to the Azure portal (https://portal.azure.com), and (from the home page) click “create a resource”.

    -

    +

    First, create a Shared Image Gallery in Azure. Browse to the Azure portal (https://portal.azure.com), and (from the home page) click “create a resource”.

    +

    Search for “Shared Image Gallery” and then click “Create”.

    Configure a subscription, resource group, and then name the Shared Image Gallery and configure what region you want it to live in. You will want to create it in the same region as your standard image repository.

    -

    +

    If you want to assign some tags to this new resource, continue to the next page. Otherwise, click “Review + Create”.

    -

    +

    On the final page, if the validation is successful, click “Create”.

    -

    +

    It should take less than a minute to create the shared image gallery. Once its created, click “Go to resource”.

    -

    +

    In the shared image gallery blade, click “Add new image definition”.

    -

    +

    On the next page, select the region where your existing image repository lives, give the image definition a name, and then fill out the rest of the information as needed. The publisher will typically be the name of your company/organization. The offer will typically be set to the name of the overall application, being that servers typically host one piece of an application (example: database servers vs. application servers). The SKU will typically be set to the name of the component within the application (for example, a web server or database server).

    -

    +

    Next, configure an image version. This should use the typical semantic format used in software development (major version, minor version, patch level). I will typically substitute the patch level with the date the image was captured. Probably not a best practice, but something that has served me well in the past.

    Next, select the source image. This will be the image that you are copying from your standard image repository. You can also configure an end of life date for the image version here if you wish. In the “Target Regions” section at the bottom, select the region where you plan to create the new VM. Also select the target storage account type.

    -

    +

    You can configure some publishing options and tags on the following pages. Though, it is not required. Click “Review + create”. After the validation passes, click “Create”.

    -

    +

    This process will take a few minutes to complete. Once its finished, click on “go to resource”. You now have an image that is available to be deployed in the north central region or the south central region.

    -
    - - - - + - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2020-11-17-azure-policy-allowed-locations-for/index.html b/public/posts/2020-11-17-azure-policy-allowed-locations-for/index.html index 1df1e9b2..4342805e 100644 --- a/public/posts/2020-11-17-azure-policy-allowed-locations-for/index.html +++ b/public/posts/2020-11-17-azure-policy-allowed-locations-for/index.html @@ -1,486 +1,303 @@ + - - - - - - - + + + Azure Policy &#8211; Allowed Locations for Resource Deployment · GeekyRyan + + - - -Azure Policy &#8211; Allowed Locations for Resource Deployment - GeekyRyan - - - - - - + - - - - - - + + + - + + + + + + + + + + + + + + - - - - - - - - + + + + - + + + - + - - - + + - - - + + + + - - - - - - + + + + - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Azure Policy &#8211; Allowed Locations for Resource Deployment

    - - -
    -
    -
    -

    Azure Policy allows us to control what actions users can perform regarding creating and managing resources in Azure. We can define policies for naming standards, require that certain extensions be installed on virtual machines, audit various resources for certain configurations… the possibilities are endless.

    +

    Azure Policy allows us to control what actions users can perform regarding creating and managing resources in Azure. We can define policies for naming standards, require that certain extensions be installed on virtual machines, audit various resources for certain configurations… the possibilities are endless.

    In this article, well focus on defining what locations users can deploy resources in. To get started, login to the Azure Portal and search for “Policy”.

    -

    +

    Click on “Definitions”. Here you will find several built-in definitions that can be applied to your resources. Definitions are a json template containing the logic for what you want to accomplish. It is worth investing some time to look through these built-in definitions.

    In the “search” field, type in “location”. Then, click on the “Allowed Locations” definition.

    -

    +

    Here you can see the json content of the definition. The “policyRule” section is the bread and butter of the definition. In this particular example, the policyRule states that if the location that the user is deploying a resource to is NOT a) in the list of allowed locations, b) global, or c) a b2c directory, then deny the deployment.

    -

    +

    Next, click on “Assign”.

    -

    +

    You can assign the policy to a subscription or resource group. You can also create exclusions in this same window, and enable or disable the policy.

    -

    +

    Click “Next”, and on the Parameters page, choose the allowed locations from the drop down menu. Then click next.

    Azure Policy has the capability to remediate non-compliant resources. An example would be having a policy that requires anti-virus be installed on all servers. If Azure Policy detected a server that did NOT have anti-virus installed, it would use a managed identity to install AV software on the server. This particular policy does not need a remediation action, so we will just click “Next” here.

    On the Review + Create window, review the resource and then click “Create”.

    Back on the Azure Policy blade, select “Assignments”. We can now see that our new policy is assigned.

    -

    +

    Back on the “Overview” page, you can track compliance for the policy. We can see here that compliance for the “Allowed Locations” policy assignment has not yet been started. This typically takes an hour or so before the compliance state is updated.

    -

    +

    Click on the Policy to get a more detailed view of compliance, view the definition, edit the assignment, and even create exemptions.

    -

    +

    -
    - + - - - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/index.html b/public/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/index.html index eae7bfca..0acd0082 100644 --- a/public/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/index.html +++ b/public/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/index.html @@ -1,477 +1,298 @@ + - - - - - - - + + + Azure VM Scale Set &#8211; Get Instance IP Address · GeekyRyan + + - - -Azure VM Scale Set &#8211; Get Instance IP Address - GeekyRyan - - - - - - + - - - - - - + + + - + + + + + + + + + + + + + + + + - - - - - - - - + + + + - + + + - + - - - + + - - - + + + + - - - - - - + + + + - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Azure VM Scale Set &#8211; Get Instance IP Address

    - - -
    -
    -
    -

    If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal.

    +

    If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal.

    There are a few options we have for retrieving information about a VMSS and its instances without using the Azure Portal. We can use PowerShell or the Azure CLI. Being that I am constantly flipping between Windows and Linux, I will detail both here.

    You will need to have the AZ module installed. To install this module, simple open PowerShell (as admin) and type in “Install-Module -Name az”. To get the IP address of the instances within a scale set, use the following script:

    -

    https://github.com/rnemeth90/Get-VmssInstanceIpAddress

    +

    https://github.com/rnemeth90/Get-VmssInstanceIpAddress

    You can also use the Azure CLI to obtain individual instance IP addresses. This method is much simpler than PowerShell, and only requires one line of code:

    -
    az vmss nic list –resource-group myResourceGroup –vmss-name myVmss | grep –w “privateIpAddress”
    +
    az vmss nic list –resource-group myResourceGroup –vmss-name myVmss | grep –w “privateIpAddress”
     
    -
    - +
    - - - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/index.html b/public/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/index.html index 979d176e..5df3c398 100644 --- a/public/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/index.html +++ b/public/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/index.html @@ -1,124 +1,94 @@ + - - - - - - - + + + Azure AD Sync &#8211; Set-MsolDirSyncEnabled : You cannot turn off Active Directory synchronization. · GeekyRyan + + - + -Azure AD Sync &#8211; Set-MsolDirSyncEnabled : You cannot turn off Active Directory synchronization. - GeekyRyan + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - + + + - - - - - + - + + + - - - - - - - - - - - - + + + + + - - - - - - - - - + + @@ -128,362 +98,211 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Azure AD Sync &#8211; Set-MsolDirSyncEnabled : You cannot turn off Active Directory synchronization.

    - - -
    -
    -
    -

    I recently ran into a situation in my lab environment that required I resync all (2000+) user accounts to Azure AD. Though this sounds complex and daunting, its actually quite simple. T

    +

    I recently ran into a situation in my lab environment that required I resync all (2000+) user accounts to Azure AD. Though this sounds complex and daunting, its actually quite simple. T

    The basic steps involve disabling sync, and then removing the user objects. This can all be done with two PowerShell commands:

    1) Set-MsolDirSyncEnabled -EnableDirSync $false

    -

    +

    2) Get-MsolUser -All | Remove-MsolUser -force

    -

    +

    The account that you are currently running the commands as will not be removed.

    To enable Azure AD Sync, you simply reverse the boolean operation on the Set-MsolDirSyncEnabled cmdlet above. However, I ran into an issue when trying to enable Azure AD Sync.

    -

    +

    After some research, it turns out you must wait a period of time (up to 12 hours in some cases) before you can make a second change to the Azure AD Sync status. This error simply means that we made a recent change to Azure AD Sync, and we must wait before making another change. To prove this, there is a “DirectorySynchronizationStatus” member for the Get-MsolCompanyInformation cmdlet. If we take a look at this member, we can see the status is “PendingDisabled”.

    -

    +

    Check the status of this periodically over the next 12 hours or so, and once it says “Enabled” or “Disabled”, you should be able to change the state once more.

    -
    - + - - - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2020-12-16-exam-az-303-microsoft-azure-architect/index.html b/public/posts/2020-12-16-exam-az-303-microsoft-azure-architect/index.html index 115f6943..74be7124 100644 --- a/public/posts/2020-12-16-exam-az-303-microsoft-azure-architect/index.html +++ b/public/posts/2020-12-16-exam-az-303-microsoft-azure-architect/index.html @@ -1,112 +1,82 @@ + - - - - - - - + + + Exam AZ-303: Microsoft Azure Architect Technologies Study Guide · GeekyRyan + + - - -Exam AZ-303: Microsoft Azure Architect Technologies Study Guide - GeekyRyan - - - - - - - - - + - - - + + + - + + + + + + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - - + + + + + + + - - - - - - - - - @@ -115,113 +85,109 @@ - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Exam AZ-303: Microsoft Azure Architect Technologies Study Guide

    - - -
    -
    -
    -

    I recently passed the AZ-303 exam. Below are some of the resources I used to prepare for the exam. In addition to the links below, I also used Alan Rodrigues’ course on Udemy.

    -

    https://www.udemy.com/course/az-102-azure-administrator-certification-transition/ +

    I recently passed the AZ-303 exam. Below are some of the resources I used to prepare for the exam. In addition to the links below, I also used Alan Rodrigues’ course on Udemy.

    +

    https://www.udemy.com/course/az-102-azure-administrator-certification-transition/

    The Udemy course and Microsoft Docs are enough to pass the exam. The course has some good practice exams and labs that align well with what you’ll see on the real exam regarding difficulty. I was scoring in the high 90’s on the Udemy exams. On the real exam, my score was 923. So, I think, if you comprehend the material well, and get high scores on Udemy practice exams, you’ll do well on the real exam.

    Just wanted to share my experience, hopefully it helps.

    @@ -232,7 +198,7 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    monitor security

  • -

    What is Azure Security Center?

    +

    What is Azure Security Center?

  • monitor performance

    @@ -241,31 +207,31 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    configure diagnostic settings on resources

  • -

    Create diagnostic settings to send platform logs and metrics to different destinations

    +

    Create diagnostic settings to send platform logs and metrics to different destinations

  • create a performance baseline for resources

  • -

    Analyzing Resource Utilization on Azure

    +

    Analyzing Resource Utilization on Azure

  • monitor for unused resources

  • -

    Quickstart: Explore and analyze costs with cost analysis

    +

    Quickstart: Explore and analyze costs with cost analysis

  • monitor performance capacity

  • -

    How to chart performance with Azure Monitor for VMs

    +

    How to chart performance with Azure Monitor for VMs

  • visualize diagnostics data using Azure Monitor

  • -

    Azure Monitor Workbooks

    +

    Azure Monitor Workbooks

  • monitor health and availability

    @@ -274,13 +240,13 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    monitor networking

  • -

    Azure Monitor for Networks

    +

    Azure Monitor for Networks

  • monitor service health

  • -

    Service Health overview

    +

    Service Health overview

  • monitor cost

    @@ -289,13 +255,13 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    monitor spend

  • -

    Quickstart: Explore and analyze costs with cost analysis

    +

    Quickstart: Explore and analyze costs with cost analysis

  • report on spend

  • -

    View and download your Microsoft Azure invoice

    +

    View and download your Microsoft Azure invoice

  • configure advanced logging

    @@ -304,13 +270,13 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    implement and configure Azure Monitor insights, including App Insights, Networks, Containers

  • -

    What is monitored by Azure Monitor?

    +

    What is monitored by Azure Monitor?

  • configure a Log Analytics workspace

  • -

    Create a Log Analytics workspace in the Azure portal

    +

    Create a Log Analytics workspace in the Azure portal

  • configure logging for workloads

    @@ -319,7 +285,7 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    initiate automated responses by using Action Groups

  • -

    Create and manage action groups in the Azure portal

    +

    Create and manage action groups in the Azure portal

  • configure and manage advanced alerts

    @@ -328,13 +294,13 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    collect alerts and metrics across multiple subscriptions

  • -

    Create, view, and manage metric alerts using Azure Monitor

    +

    Create, view, and manage metric alerts using Azure Monitor

  • view Alerts in Azure Monitor logs

  • -

    Create, view, and manage activity log alerts by using Azure Monitor

    +

    Create, view, and manage activity log alerts by using Azure Monitor

  • Implement storage accounts

    @@ -343,55 +309,55 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    select storage account options based on a use case

  • -

    Create a storage account

    +

    Create a storage account

  • configure Azure Files and blob storage

  • -

    Create an Azure file share

    +

    Create an Azure file share

  • -

    Quickstart: Upload, download, and list blobs with the Azure portal

    +

    Quickstart: Upload, download, and list blobs with the Azure portal

  • configure network access to the storage account

  • -

    Configure Azure Storage firewalls and virtual networks

    +

    Configure Azure Storage firewalls and virtual networks

  • implement Shared Access Signatures and access policies

  • -

    Grant limited access to Azure Storage resources using shared access signatures (SAS)

    +

    Grant limited access to Azure Storage resources using shared access signatures (SAS)

  • -

    Define a stored access policy

    +

    Define a stored access policy

  • implement Azure AD authentication for storage

  • -

    Authorize access to blobs and queues using Azure Active Directory

    +

    Authorize access to blobs and queues using Azure Active Directory

  • manage access keys

  • -

    Manage storage account access keys

    +

    Manage storage account access keys

  • implement Azure storage replication

  • -

    Configure object replication for block blobs

    +

    Configure object replication for block blobs

  • implement Azure storage account failover

  • -

    Disaster recovery and storage account failover

    +

    Disaster recovery and storage account failover

  • Implement VMs for Windows and Linux

    @@ -400,37 +366,37 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    configure High Availability

  • -

    Manage the availability of Linux virtual machines

    +

    Manage the availability of Linux virtual machines

  • configure storage for VMs

  • -

    Introduction to Azure managed disks

    +

    Introduction to Azure managed disks

  • select virtual machine size

  • -

    Sizes for virtual machines in Azure

    +

    Sizes for virtual machines in Azure

  • implement Azure Dedicated Hosts

  • -

    Deploy VMs and scale sets to dedicated hosts using the portal

    +

    Deploy VMs and scale sets to dedicated hosts using the portal

  • deploy and configure scale sets

  • -

    Quickstart: Create a virtual machine scale set in the Azure portal

    +

    Quickstart: Create a virtual machine scale set in the Azure portal

  • configure Azure Disk Encryption

  • -

    Azure Disk Encryption for Windows VMs

    +

    Azure Disk Encryption for Windows VMs

  • Automate deployment and configuration of resources

    @@ -439,43 +405,43 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    save a deployment as an Azure Resource Manager template

  • -

    Single and multi-resource export to a template in Azure portal

    +

    Single and multi-resource export to a template in Azure portal

  • modify Azure Resource Manager template

  • -

    What are ARM templates?

    +

    What are ARM templates?

  • evaluate location of new resources

  • -

    View activity logs to monitor actions on resources

    +

    View activity logs to monitor actions on resources

  • configure a virtual disk template

  • -

    Create a managed image of a generalized VM in Azure

    +

    Create a managed image of a generalized VM in Azure

  • deploy from a template

  • -

    Deploy Azure virtual machines from VHD templates

    +

    Deploy Azure virtual machines from VHD templates

  • manage a template library

  • -

    Shared Image Galleries overview

    +

    Shared Image Galleries overview

  • create and execute an automation runbook

  • -

    Getting Started With Azure Automation – Runbook Management

    +

    Getting Started With Azure Automation – Runbook Management

  • Implement virtual networking

    @@ -484,13 +450,13 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    implement VNet to VNet connections

  • -

    Configure a VNet-to-VNet VPN gateway connection by using the Azure portal

    +

    Configure a VNet-to-VNet VPN gateway connection by using the Azure portal

  • implement VNet peering

  • -

    Virtual network peering

    +

    Virtual network peering

  • Implement Azure Active Directory

    @@ -499,67 +465,67 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    add custom domains

  • -

    Add your custom domain name using the Azure Active Directory portal

    +

    Add your custom domain name using the Azure Active Directory portal

  • configure Azure AD Identity Protection

  • -

    What is Identity Protection?

    +

    What is Identity Protection?

  • implement self-service password reset

  • -

    Tutorial: Enable users to unlock their account or reset passwords using Azure Active Directory self-service password reset

    +

    Tutorial: Enable users to unlock their account or reset passwords using Azure Active Directory self-service password reset

  • implement Conditional Access including MFA

  • -

    Conditional Access: Require MFA for all users

    +

    Conditional Access: Require MFA for all users

  • configure user accounts for MFA

  • -

    Enable per-user Azure AD Multi-Factor Authentication to secure sign-in events

    +

    Enable per-user Azure AD Multi-Factor Authentication to secure sign-in events

  • configure fraud alerts

  • -

    Fraud alert

    +

    Fraud alert

  • configure bypass options

  • -

    One-time bypass

    +

    One-time bypass

  • configure Trusted IPs

  • -

    Trusted IPs

    +

    Trusted IPs

  • configure verification methods

  • -

    Authentication methods

    +

    Authentication methods

  • implement and manage guest accounts

  • -

    Quickstart: Add guest users to your directory in the Azure portal

    +

    Quickstart: Add guest users to your directory in the Azure portal

  • manage multiple directories

  • -

    Understand how multiple Azure Active Directory organizations interact

    +

    Understand how multiple Azure Active Directory organizations interact

  • Implement and manage hybrid identities

    @@ -568,31 +534,31 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    install and configure Azure AD Connect

  • -

    Getting started with Azure AD Connect using express settings

    +

    Getting started with Azure AD Connect using express settings

  • identity synchronization options

  • -

    Azure AD Connect user sign-in options

    +

    Azure AD Connect user sign-in options

  • configure and manage password sync and password writeback

  • -

    Tutorial: Enable Azure Active Directory self-service password reset writeback to an on-premises environment

    +

    Tutorial: Enable Azure Active Directory self-service password reset writeback to an on-premises environment

  • configure single sign-on

  • -

    Azure Active Directory Seamless Single Sign-On: Quickstart

    +

    Azure Active Directory Seamless Single Sign-On: Quickstart

  • use Azure AD Connect Health

  • -

    What is Azure AD Connect Health?

    +

    What is Azure AD Connect Health?

  • Implement Management and Security Solutions (25-30%)

    @@ -614,25 +580,25 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    recommend target infrastructure

  • -

    Migrate Hyper-V VMs to Azure

    +

    Migrate Hyper-V VMs to Azure

  • implement Azure Backup for VMs

  • -

    Back up an Azure VM from the VM settings

    +

    Back up an Azure VM from the VM settings

  • implement disaster recovery

  • -

    Tutorial: Set up disaster recovery for Azure VMs

    +

    Tutorial: Set up disaster recovery for Azure VMs

  • implement Azure Update Management

  • -

    Enable Update Management for an Azure VM

    +

    Enable Update Management for an Azure VM

  • Implement load balancing and network security

    @@ -641,52 +607,52 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    implement Azure Load Balancer

  • -

    What is Azure Load Balancer?

    +

    What is Azure Load Balancer?

  • implement an application gateway

  • -

    What is Azure Application Gateway?

    +

    What is Azure Application Gateway?

  • implement a Web Application Firewall

  • -

    What is Azure Web Application Firewall?

    +

    What is Azure Web Application Firewall?

  • implement Azure Firewall

  • -

    What is Azure Firewall?

    +

    What is Azure Firewall?

  • implement the Azure Front Door Service

  • -

    Quickstart: Create a Front Door for a highly available global web application

    +

    Quickstart: Create a Front Door for a highly available global web application

  • implement Azure Traffic Manager

  • -

    What is Traffic Manager?

    +

    What is Traffic Manager?

  • implement Network Security Groups and Application Security Groups

  • -

    Network security groups

    +

    Network security groups

  • -

    Application security groups

    +

    Application security groups

  • implement Bastion

  • -

    Azure Bastion documentation

    +

    Azure Bastion documentation

  • Implement and manage Azure governance solutions

    @@ -695,61 +661,61 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    create and manage hierarchical structure that contains management groups

  • -

    What are Azure management groups?

    +

    What are Azure management groups?

  • subscriptions and resource groups

  • -

    Organize your Azure resources effectively

    +

    Organize your Azure resources effectively

  • assign RBAC roles

  • -

    Add or remove Azure role assignments using the Azure portal

    +

    Add or remove Azure role assignments using the Azure portal

  • create a custom RBAC role

  • -

    Azure custom roles

    +

    Azure custom roles

  • configure access to Azure resources by assigning roles

  • -

    Add or remove Azure role assignments using the Azure portal

    +

    Add or remove Azure role assignments using the Azure portal

  • configure management access to Azure

  • -

    Manage access to an Azure subscription by using Azure role-based access control (RBAC)

    +

    Manage access to an Azure subscription by using Azure role-based access control (RBAC)

  • interpret effective permissions

  • -

    Quickstart: Check access for a user to Azure resources

    +

    Quickstart: Check access for a user to Azure resources

  • set up and perform an access review

  • -

    What are Azure AD access reviews?

    +

    What are Azure AD access reviews?

  • implement and configure an Azure Policy

  • -

    Quickstart: Create a policy assignment to identify non-compliant resources

    +

    Quickstart: Create a policy assignment to identify non-compliant resources

  • implement and configure an Azure Blueprint

  • -

    What is Azure Blueprints?

    +

    What is Azure Blueprints?

  • Manage security for applications

    @@ -758,19 +724,19 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    implement and configure KeyVault

  • -

    Configure and manage secrets in Azure Key Vault

    +

    Configure and manage secrets in Azure Key Vault

  • implement and configure Managed Identities

  • -

    What are managed identities for Azure resources?

    +

    What are managed identities for Azure resources?

  • register and manage applications in Azure AD

  • -

    Quickstart: Register an application with the Microsoft identity platform

    +

    Quickstart: Register an application with the Microsoft identity platform

  • Implement Solutions for Apps (10-15%)

    @@ -780,49 +746,49 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    create and configure Azure App Service

  • -

    Quickstart: Create an ASP.NET Core web app in Azure

    +

    Quickstart: Create an ASP.NET Core web app in Azure

  • create an App Service Web App for Containers

  • -

    Deploy and run a containerized web app with Azure App Service

    +

    Deploy and run a containerized web app with Azure App Service

  • create and configure an App Service plan

  • -

    Manage an App Service plan in Azure

    +

    Manage an App Service plan in Azure

  • configure an App Service

  • -

    Configure an App Service app in the Azure portal

    +

    Configure an App Service app in the Azure portal

  • configure networking for an App Service

  • -

    Integrate your app with an Azure virtual network

    +

    Integrate your app with an Azure virtual network

  • create and manage deployment slots

  • -

    Set up staging environments in Azure App Service

    +

    Set up staging environments in Azure App Service

  • implement Logic Apps

  • -

    Quickstart: Create your first Logic Apps workflow – Azure portal

    +

    Quickstart: Create your first Logic Apps workflow – Azure portal

  • implement Azure Functions

  • -

    Create your first function in the Azure portal

    +

    Create your first function in the Azure portal

  • Implement container-based applications

    @@ -831,25 +797,25 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    create a container image

  • -

    Quickstart: Build and run a container image using Azure Container Registry Tasks

    +

    Quickstart: Build and run a container image using Azure Container Registry Tasks

  • configure Azure Kubernetes Service

  • -

    Quickstart: Deploy an Azure Kubernetes Service (AKS) cluster using the Azure portal

    +

    Quickstart: Deploy an Azure Kubernetes Service (AKS) cluster using the Azure portal

  • publish and automate image deployment to the Azure Container Registry

  • -

    Deploy to Azure Container Instances from Azure Container Registry

    +

    Deploy to Azure Container Instances from Azure Container Registry

  • publish a solution on an Azure Container Instance

  • -

    Quickstart: Deploy a container instance in Azure using the Azure portal

    +

    Quickstart: Deploy a container instance in Azure using the Azure portal

  • Implement and Manage Data Platforms (10-15%)

    @@ -859,19 +825,19 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    configure storage account tables

  • -

    Quickstart: Create an Azure Storage table in the Azure portal

    +

    Quickstart: Create an Azure Storage table in the Azure portal

  • select appropriate CosmosDB APIs

  • -

    Choose the appropriate API for Azure Cosmos DB

    +

    Choose the appropriate API for Azure Cosmos DB

  • set up replicas in CosmosDB

  • -

    Distribute your data globally with Azure Cosmos DB

    +

    Distribute your data globally with Azure Cosmos DB

  • Implement Azure SQL databases

    @@ -880,261 +846,112 @@

    Exam AZ-303: Microsoft Azure Architect Technologie

    configure Azure SQL database settings

  • -

    Quickstart: Create an Azure SQL Database single database

    +

    Quickstart: Create an Azure SQL Database single database

  • implement Azure SQL Database managed instances

  • -

    What is Azure SQL Managed Instance?

    +

    What is Azure SQL Managed Instance?

  • configure HA for an Azure SQL database

  • -

    High availability for Azure SQL Database and SQL Managed Instance

    +

    High availability for Azure SQL Database and SQL Managed Instance

  • publish an Azure SQL database

  • -

    - - - + - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-01-14-active-directory-migration-toolkit-the-rpc-server-is-unavailable/index.html b/public/posts/2022-01-14-active-directory-migration-toolkit-the-rpc-server-is-unavailable/index.html index 7b07c6d5..31a70cb7 100644 --- a/public/posts/2022-01-14-active-directory-migration-toolkit-the-rpc-server-is-unavailable/index.html +++ b/public/posts/2022-01-14-active-directory-migration-toolkit-the-rpc-server-is-unavailable/index.html @@ -1,441 +1,276 @@ + - - - - - - - + + + Active Directory Migration Toolkit The RPC Server is Unavailable · GeekyRyan + + - + -Active Directory Migration Toolkit The RPC Server is Unavailable - GeekyRyan + + + + + + + - - - - - - - - + + + + + + + + + - + + + + - - - - - + + + - - - + - + + + - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - -
    -
    - - - -
    -
    -
    -

    Active Directory Migration Toolkit The RPC Server is Unavailable

    - - -
    -
    -
    -

    When migrating computer objects using the Active Directory Migration Tool, you may encounter the following error:

    -

    -

    In addition, the Migration Log may show the following error:

    -

    -

    This is typically caused by a host-side firewall. To resolve this, deploy a GPO to disable the Windows firewall prior to migrating the computer account. I like to create a special OU for computers (I typically name it “PreMigration”) that I will move computer objects to prior to migrating them. This OU will have two policies applied. One to disable the Windows Firewall and another to start the Remote Registry service. Both are required for the computer object to successfully migrate.

    - -
    - - - - - - +
    - - - + - - - - - - +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/index.html b/public/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/index.html index b63cf15d..d7e49428 100644 --- a/public/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/index.html +++ b/public/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/index.html @@ -1,467 +1,284 @@ + - - - - - - - + + + Azure Devops &#8211; Self Hosted Agent Service Won&#8217;t Start &#8211; Incorrect Function · GeekyRyan + + - + -Azure Devops &#8211; Self Hosted Agent Service Won&#8217;t Start &#8211; Incorrect Function - GeekyRyan - - + + + - - + + + - + + + + + + + + + + + - - + + + + + + + - - - - - - - - - + - + + - - - - - - - - - - - - + + + + + + - - - - - - + + - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - -
    -
    - - - -
    -
    -
    -

    Azure Devops &#8211; Self Hosted Agent Service Won&#8217;t Start &#8211; Incorrect Function

    - - -
    -
    -
    -

    I setup a self hosted agent for Azure Devops this morning on Server 2012 R2 (legacy Visual Studio dependencies…) and found that I was unable to start the service. The error I received was “Error 1 Incorrect Function” when attempting to start the service in services.msc.

    -

    I was attempting to run the agent from within my user profile downloads folder. I originally was not aware the service would be running from this directory. I thought it would copy its binary files to program files directory or programdata, like 99% of all other apps. The service installs and attempts to run itself as the “network service” authority. This account does not have permission to a user profile folder by default, and the installation script is not able to grant it permission for some reason (I didn’t investigate this further). I removed the agent, moved the installation files to the root of c:, and then reinstalled. The agent service is now able to start successfully.

    - -
    - - - - - - - +
    - - - - - - + - - - - - - +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/posts/2022-01-14-azure-tenant-maintenance-purge-empty-resource-groups/index.html b/public/posts/2022-01-14-azure-tenant-maintenance-purge-empty-resource-groups/index.html index eb13dd4a..22511595 100644 --- a/public/posts/2022-01-14-azure-tenant-maintenance-purge-empty-resource-groups/index.html +++ b/public/posts/2022-01-14-azure-tenant-maintenance-purge-empty-resource-groups/index.html @@ -1,115 +1,82 @@ + - - - - - - - + + + Azure Tenant Maintenance &#8211; Purge Empty Resource Groups · GeekyRyan + + - - -Azure Tenant Maintenance &#8211; Purge Empty Resource Groups - GeekyRyan - - - - - - + - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - + + + + - - + + + - - - - - + - + + + - - - - - - - - - - - - + + + + + - - - - - - - - - + + @@ -119,348 +86,212 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - - -
    -
    - + + + -
    -
    -
    -

    Azure Tenant Maintenance &#8211; Purge Empty Resource Groups

    - -
    +
    + +
    +
    +
    +
    +

    + + Azure Tenant Maintenance &#8211; Purge Empty Resource Groups + +

    +
    + -
    -

    This will be the first article in a series about maintaining Azure tenants and subscriptions.

    +
    + +
    + +

    This will be the first article in a series about maintaining Azure tenants and subscriptions.

    If you currently, or have ever, worked in a large Azure environment, you know how easily resource creep can occur. Resource Groups, VM disks and network interfaces, network security groups, etc. can easily fall out of sight and be forgotten about. This isn’t a big concern for resources that are free of cost, like resource groups. However, if you delete several virtual machines, the disks that were attached to those virtual machines linger, and you continue to pay the cost of storing them.

    In this blog post, we will review a script I created for removing empty resource groups. We will then add this script to an Azure Automation Account and link it to a schedule. We will assume you already have an Azure Automation Account in existence, and the Automation Account has a credential object named ‘AzureRunAsConnection’.

    To get started, you can download the script here:

    -

    https://github.com/rnemeth90/azure-automation/blob/master/clean-empty-resource-groups.ps1

    +

    https://github.com/rnemeth90/azure-automation/blob/master/clean-empty-resource-groups.ps1

    This particular runbook will require that the “AZ.Resources” module be loaded in the Automation Account. To import this module, go to your automation account and then click on “Modules” under “Shared Resources”. Then, click on “Browse Gallery”.

    -

    +

    In the search bar, type in “Az.resources”, then click on the module and click “Import”. If you see a message like this, you will need to add any modules that az.resources depends on before importing it.

    -

    +

    You can go back and add those modules using the same process, and then attempt to import the “Az.resources” module again. Importing these modules may take several minutes. In my experience, it takes around 10-15 minutes.

    Once these modules are imported you can import the PowerShell runbook you downloaded earlier from Github. To do that, browse to the Runbooks section of your Automation Account and then click “Import a Runbook”:

    -

    +

    In the context menu that appears, browse to the runbook and upload it, choose “PowerShell” as the runbook type, and then click Create:

    -

    +

    In the Editor Pane, click on “Test Pane”. This will bring you to the Test Pane for the runbook. This will allow you to test the runbook before running it in your environment. Click “Start” in the Test Pane. This particular runbook will output to screen any changes it will make, so you can see the results here.

    As you can see here, the runbook did find some empty resource groups, but did not remove them:

    -

    +

    This is because we have a variable in the runbook that controls whether or not any write/update actions will be taken on resources. Click the X in the upper right corner to go back to the editor, and change the value in the screenshot below from “0” to “1”.

    -

    +

    If you’d like, you can test the runbook again, or you can click “Publish” to publish it to your Automation Account. Once it’s published, you can link it to a schedule so that it runs automatically.

    Click “Publish”:

    -

    <

    +

    <

    Then, on the Runbook page, click “Schedules”, and then “Add a schedule”:

    -

    +

    Fill out the wizard that pops up to create a schedule and link it to your workbook. This concludes this article.

    In the next post, we will take a look at removing empty resource groups automatically. Stay tuned.

    -
    - +
    - - - -
    - - - - - - + + + + + + + + +
    +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    + + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-01-14-continuous-deployment-models/index.html b/public/posts/2022-01-14-continuous-deployment-models/index.html index fd938623..e800995a 100644 --- a/public/posts/2022-01-14-continuous-deployment-models/index.html +++ b/public/posts/2022-01-14-continuous-deployment-models/index.html @@ -1,115 +1,86 @@ + - - - - - - - + + + Continuous Deployment Models · GeekyRyan + + - - -Continuous Deployment Models - GeekyRyan - - - - - - - - - + - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + - - + + + - - - - - + - + + + - - - - - - - - - - - - + + + + + - - - - - - - - - + + @@ -119,396 +90,250 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Continuous Deployment Models

    - - -
    -
    -
    -

    When deploying new software releases to servers or (insert -as-a-service> here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments.

    -

    Blue/Green Deployments - - - - - -

    Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. Instead, it gets deployed to another set of servers (blue) first. Since the blue servers are not currently serving any traffic for users, the deployment has no impact. However, once the deployment has been completed successfully and tested, users will be directed to the new deployment (blue). You can control all user traffic or a subset of user traffic if your load balancer supports it (referred to as ‘Progressive Exposure’).

    +

    When deploying new software releases to servers or (insert -as-a-service> here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments.

    +

    + Blue/Green Deployments + + + Link to heading + +

    +

    Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. Instead, it gets deployed to another set of servers (blue) first. Since the blue servers are not currently serving any traffic for users, the deployment has no impact. However, once the deployment has been completed successfully and tested, users will be directed to the new deployment (blue). You can control all user traffic or a subset of user traffic if your load balancer supports it (referred to as ‘Progressive Exposure’).

    The next release will then repeat the same process. Blue would be the current production environment, so you would first deploy to the green servers. This model requires two sets of identical hosts and a load balancer or reverse proxy in front of them. If there are any unexpected issues with the new release, it is straightforward to switch back to the previous release. The disadvantage to this type of model is that it requires having redundant environments (and potentially wasted resources). However, this is less of a concern if using container orchestration platforms such as Kubernetes.

    -

    Blue Green deployment model

    -

    Immutable Servers - - - - - -

    There is an alternative method of blue/green deployments called “immutable servers”. This method is identical to blue/green deployments as described above. However, after switching user traffic over to the servers with the new release, the old servers are destroyed. They are not used again. This type of model becomes particularly efficient when using a pipeline that is capable of creating servers for you (i.e., Azure DevOps Pipelines)

    -

    Canary Deployments - - - - - -

    In a canary deployment, not all users are routed to the new release immediately. Only a limited percentage of users get access to the new release. These users are the canaries. They should be monitored closely, so it is important to be using Not all users are routed to the new release immediately in a canary deployment. Only a limited percentage of users get access to the latest release. These users are the canaries.

    +

    Blue Green deployment model

    +

    + Immutable Servers + + + Link to heading + +

    +

    There is an alternative method of blue/green deployments called “immutable servers”. This method is identical to blue/green deployments as described above. However, after switching user traffic over to the servers with the new release, the old servers are destroyed. They are not used again. This type of model becomes particularly efficient when using a pipeline that is capable of creating servers for you (i.e., Azure DevOps Pipelines)

    +

    + Canary Deployments + + + Link to heading + +

    +

    In a canary deployment, not all users are routed to the new release immediately. Only a limited percentage of users get access to the new release. These users are the canaries. They should be monitored closely, so it is important to be using Not all users are routed to the new release immediately in a canary deployment. Only a limited percentage of users get access to the latest release. These users are the canaries.

    Organizations should monitor the canaries closely, so it is essential to be using monitoring software capable of looking at the statistics of a web application from the users’ perspective (for example, Application Insights). The number of canaries can increase until all traffic is directed to the new release over time. The most significant advantage of this method is limited exposure to issues. If a problem appears after the release is deployed, only a small subset of users will experience it. After you fix the issues and redeploy the release, it’s best to select a different group of users to be canaries.

    -

    Ring Based Deployments - - - - - -

    A ring-based deployment has multiple production environments. Each serves a limited number of users, similar to a canary deployment. However, you can have as many production environments as you want with a ring-based deployment. New releases are deployed to the rings one by one over time.

    -

    Feature Flag Deployments - - - - - -

    Feature flags are used to expose new features to sets of users slowly. Unlike the other deployment models, they are not implemented in the infrastructure. Instead, they are typically implemented and enabled in code or database. An example would be a feature flag in a database that gives users access to a button on your web page. A developer could enable the flag for a set of users. These users would be able to see the button; other users would not. Feature flags can even toggle bug fixes or performance improvements.

    +

    + Ring Based Deployments + + + Link to heading + +

    +

    A ring-based deployment has multiple production environments. Each serves a limited number of users, similar to a canary deployment. However, you can have as many production environments as you want with a ring-based deployment. New releases are deployed to the rings one by one over time.

    +

    + Feature Flag Deployments + + + Link to heading + +

    +

    Feature flags are used to expose new features to sets of users slowly. Unlike the other deployment models, they are not implemented in the infrastructure. Instead, they are typically implemented and enabled in code or database. An example would be a feature flag in a database that gives users access to a button on your web page. A developer could enable the flag for a set of users. These users would be able to see the button; other users would not. Feature flags can even toggle bug fixes or performance improvements.

    I will cover implementing blue/green deployments in Azure using Azure DevOps and App Services in a future article.

    -
    - - - + - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/index.html b/public/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/index.html index dc511a6b..41c6a986 100644 --- a/public/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/index.html +++ b/public/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/index.html @@ -1,482 +1,299 @@ + - - - - - - - + + + Deploy Azure VMs Using Azure Devops CI/CD Pipeline · GeekyRyan + + - + -Deploy Azure VMs Using Azure Devops CI/CD Pipeline - GeekyRyan + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + - - - - - - - - - + - + + + - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Deploy Azure VMs Using Azure Devops CI/CD Pipeline

    - - -
    -
    -
    -

    This article assumes that you have already created a pipeline in Azure Devops and have it linked to an Azure Devops repo. You will need to create a variable named $vmpassword and assign it the value stored in your key vault.

    +

    This article assumes that you have already created a pipeline in Azure Devops and have it linked to an Azure Devops repo. You will need to create a variable named $vmpassword and assign it the value stored in your key vault.

    To create a release pipeline that will automatically create a VM (using the password stored in key vault for the local administrator account), do the following:

    1. Create a new release pipeline
    -

    -

    3. In the “select a template” box, choose “Empty Job”

    -

    4. Select “Tasks” in the navigation bar, and then select the appropriate stage. For simplicities sake, we will be using 1 stage within this release.

    -

    5. Click on the “+” in the Agent job bar, and then in the “Add tasks” section, type in “Key Vault”. Click “Azure Key Vault” and then click “Add”.

    -

    6. Click on the “Azure Key Vault:” task to configure it. Select your subscription, Key Vault, and the secrets filter. You can also create the $vmpassword variable as a variable within your devops project, rather than assigning it as a secret filter for the release.

    -

    7. In your Key Vault, you need to grant the devops account access to the Key Vault. To do this, go to your Key Vault and create a new access policy. This policy will be assigned to a service principal that is being used by your Azure Devops project. To find the ID of this service principal, go to your project settings, and under “Pipelines”, click on “Service Connections”. Then select the service connection that resembles your subscription. After doing this, click “Manage Service Principal”. In the service principal window, click “Manifest” and then find the “name” tag within the JSON.

    +

    +

    3. In the “select a template” box, choose “Empty Job”

    +

    4. Select “Tasks” in the navigation bar, and then select the appropriate stage. For simplicities sake, we will be using 1 stage within this release.

    +

    5. Click on the “+” in the Agent job bar, and then in the “Add tasks” section, type in “Key Vault”. Click “Azure Key Vault” and then click “Add”.

    +

    6. Click on the “Azure Key Vault:” task to configure it. Select your subscription, Key Vault, and the secrets filter. You can also create the $vmpassword variable as a variable within your devops project, rather than assigning it as a secret filter for the release.

    +

    7. In your Key Vault, you need to grant the devops account access to the Key Vault. To do this, go to your Key Vault and create a new access policy. This policy will be assigned to a service principal that is being used by your Azure Devops project. To find the ID of this service principal, go to your project settings, and under “Pipelines”, click on “Service Connections”. Then select the service connection that resembles your subscription. After doing this, click “Manage Service Principal”. In the service principal window, click “Manifest” and then find the “name” tag within the JSON.

    8. Now go back to your key vault, and assign an access policy for this service principal. Grant the principal read and list for secrets.

    -

    9. Add another agent job for the task (see step 6) and search for “azure cli”. Click on “Add” for Azure CLI. Configure the settings for this job as below:

    -

    10. Save and run your pipeline. Give it some time to complete, and go take a look at your newly created VM. This is just a very simple example of creating a server as part of a CI/CD pipeline. You can then deploy your code to it, run some tests, destroy them VM, etc. Completely automated.

    +

    9. Add another agent job for the task (see step 6) and search for “azure cli”. Click on “Add” for Azure CLI. Configure the settings for this job as below:

    +

    10. Save and run your pipeline. Give it some time to complete, and go take a look at your newly created VM. This is just a very simple example of creating a server as part of a CI/CD pipeline. You can then deploy your code to it, run some tests, destroy them VM, etc. Completely automated.

    -
    - - - + - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-01-14-wsus-update-files-not-downloading/index.html b/public/posts/2022-01-14-wsus-update-files-not-downloading/index.html index cd3c1c56..01326c87 100644 --- a/public/posts/2022-01-14-wsus-update-files-not-downloading/index.html +++ b/public/posts/2022-01-14-wsus-update-files-not-downloading/index.html @@ -1,118 +1,85 @@ + - - - - - - - + + + WSUS: Update Files Not Downloading · GeekyRyan + + - + -WSUS: Update Files Not Downloading - GeekyRyan + + + + + + + - - - - - - - - - + + + + + + + + + - + + + + - - - - - - - - - - - - - - + + + - + - - - - - - - - - - + + + - - - - - - - - - + + + + + - - - - - - - - - + + @@ -122,326 +89,194 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - - -
    -
    - + + + -
    -
    -
    -

    WSUS: Update Files Not Downloading

    - -
    +
    + +
    +
    +
    +
    +

    + + WSUS: Update Files Not Downloading + +

    +
    + -
    -

    This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates:

    -

    +
    + +
    + +

    This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates:

    +

    You may also see this event (or similar) in the Event Log.

    -

    +

    This problem is caused by not specifying a valid path when assigning the WSUS content drive when first installing the role. The first time you load the WSUS console after installing the role, you will be prompted to specify the path to store Windows Update files. WSUS does not like to have its content directory be the root of a partition. For example, if I were to specify “e:” as the path for the Windows Update content, the wizard would give you an error message stating that the path is not valid. However, it doesn’t prompt you to re-enter the path if you click close. The WSUS console opens immediately after and that invalid path is where WSUS will try to store your update files. This is and has been a known bug for a while and needs to be addressed by Microsoft. Evidence of the invalid path can be found in the registry under:

    HKLM\Software\Microsoft\UpdateServices\Server\SetupContentDir

    -

    +

    If you come across this problem, you can change the ContentDir above to a valid path. Keep in mind that it cannot be the root of a partition. You need to specify a drive letter with a subfolder (eg: e:wsus).

    -

    +

    The other option is to reinstall the WSUS role. If you remove the role, the WID database is not removed, unless you remove that role as well (or manually delete the database). This means that when you reinstall the WSUS role, it will be able to use that same database and any clients that have contacted the WSUS server will immediately show up in the console. The same is true for update metadata. The new WSUS installation will still have the same approvals, denials, etc. as the old installation.

    Regardless of what option you choose, I suggest rebooting the server after you make the changes.

    -
    - - - - +
    - -
    - - - - - - + + + + + + + + +
    +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    + + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-01-16-azure-kubernetes-sftp-solution/index.html b/public/posts/2022-01-16-azure-kubernetes-sftp-solution/index.html index 3099919d..4932b7eb 100644 --- a/public/posts/2022-01-16-azure-kubernetes-sftp-solution/index.html +++ b/public/posts/2022-01-16-azure-kubernetes-sftp-solution/index.html @@ -1,237 +1,220 @@ + - - - - - - - + + + Azure Kubernetes sFTP Solution · GeekyRyan + + - + -Azure Kubernetes sFTP Solution - GeekyRyan + + + + + + + - - - - - - - - + + + + + + + + + + + + + + - + + + + - - - - - + + + - - - + - + + + - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Azure Kubernetes sFTP Solution

    - - -
    -
    -
    -

    In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault.

    +

    In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault.

    Here is the link to my Github account where you can download the code mentioned in this article:

    -

    https://github.com/rnemeth90/kubernetes-sftp

    +

    https://github.com/rnemeth90/kubernetes-sftp

    We will work through the following steps in this article:

    1. Deploy the AzureFile CSI driver to the AKS cluster
    2. @@ -242,416 +225,255 @@

      Azure Kubernetes sFTP Solution

    First, you will need to deploy the Azure Files CSI driver to your AKS cluster. AKS uses this daemon set to dynamically provision/destroy Azure NFSv4 File Shares. The Azure Files CSI driver creates a storage account in the node pool resource group, in which it will then provision the file share.

    Deploying the Azure Files CSI driver is a simple task. You will need to run this script:

    -
    curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/install-driver.sh | bash -s master --
    +
    curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/install-driver.sh | bash -s master --
     

    You can use the following commands to verify that the daemon set has exists:

    -
    kubectl -n kube-system get pod -o wide --watch -l app=csi-azurefile-controller
    -
    -kubectl -n kube-system get pod -o wide --watch -l app=csi-azurefile-node
    +
    kubectl -n kube-system get pod -o wide --watch -l app=csi-azurefile-controller
    +
    +kubectl -n kube-system get pod -o wide --watch -l app=csi-azurefile-node
     
    Next, you need to create a storage class by deploying this yaml file: -
    kubectl create -f https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/example/storageclass-azurefile-nfs.yaml
    +
    kubectl create -f https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/example/storageclass-azurefile-nfs.yaml
     

    Read more about the AzureFiles CSI driver at the following Github link:

    -

    https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/install-driver-on-aks.md

    -
    apiVersion: v1
    -kind: ConfigMap
    -metadata:
    -  creationTimestamp: null
    -  name: testcm
    -data:
    -  init.sh: |-
    -    #!/bin/bash
    -
    -    CONF_FILE="/etc/sftp/users.conf"
    -    KEYVAULT="Insert name of Key Vault"
    -    AZ_SPN_ID="Insert service principal Id"
    -    AZ_SPN_PASSWORD="Insert service principal password"
    -    AZ_SPN_TENANT_ID="Insert Az AAD Tenant Id"
    -    AZ_SUBSCRIPTION_ID="Insert Az Subscription Id"
    -
    -    az login --service-principal --username "${AZ_SPN_ID}" --password "${AZ_SPN_PASSWORD}" --tenant "${AZ_SPN_TENANT_ID}"
    -    az account set --subscription "${AZ_SUBSCRIPTION_ID}"
    -
    -    SECRETS+=($(az keyvault secret list --vault-name $KEYVAULT --query "[].id" -o tsv))
    -
    -    chmod 755 /home
    -
    -    if [[ -e $CONF_FILE ]]; then
    -        rm -rf "${CONF_FILE}"
    -        touch $CONF_FILE
    -    else
    -        touch $CONF_FILE
    -    fi
    -
    -    for SECRET in "${SECRETS[@]}"; do
    -        SECRETNAME=$(basename $SECRET |  tr -d '\r')
    -        SECRETVALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $SECRETNAME --query 'value' | tr -d '"' | tr -d '\r')
    -
    -        echo "$SECRETNAME:$SECRETVALUE:::upload" >> $CONF_FILE
    -    done
    -
    -    if [[ ! -s $CONF_FILE ]]; then
    -        echo "** ERROR: user.conf is empty" 1>&2
    -        exit 1
    -    fi    
    -

    The initContainer will use this configMap to read secrets from an Azure Key Vault and then write the secrets to the users.conf file. The users.conf file contains user account information. In the Key Vault, the secret name should be the username and the secret value should be the password. This Key Vault must exist and contain the secrets prior to deploying this solution.

    +

    https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/install-driver-on-aks.md

    +
    apiVersion: v1
    +kind: ConfigMap
    +metadata:
    +  creationTimestamp: null
    +  name: testcm
    +data:
    +  init.sh: |-
    +    #!/bin/bash
    +
    +    CONF_FILE="/etc/sftp/users.conf"
    +    KEYVAULT="Insert name of Key Vault"
    +    AZ_SPN_ID="Insert service principal Id"
    +    AZ_SPN_PASSWORD="Insert service principal password"
    +    AZ_SPN_TENANT_ID="Insert Az AAD Tenant Id"
    +    AZ_SUBSCRIPTION_ID="Insert Az Subscription Id"
    +
    +    az login --service-principal --username "${AZ_SPN_ID}" --password "${AZ_SPN_PASSWORD}" --tenant "${AZ_SPN_TENANT_ID}"
    +    az account set --subscription "${AZ_SUBSCRIPTION_ID}"
    +
    +    SECRETS+=($(az keyvault secret list --vault-name $KEYVAULT --query "[].id" -o tsv))
    +
    +    chmod 755 /home
    +
    +    if [[ -e $CONF_FILE ]]; then
    +        rm -rf "${CONF_FILE}"
    +        touch $CONF_FILE
    +    else
    +        touch $CONF_FILE
    +    fi
    +
    +    for SECRET in "${SECRETS[@]}"; do
    +        SECRETNAME=$(basename $SECRET |  tr -d '\r')
    +        SECRETVALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $SECRETNAME --query 'value' | tr -d '"' | tr -d '\r')
    +
    +        echo "$SECRETNAME:$SECRETVALUE:::upload" >> $CONF_FILE
    +    done
    +
    +    if [[ ! -s $CONF_FILE ]]; then
    +        echo "** ERROR: user.conf is empty" 1>&2
    +        exit 1
    +    fi    
    +

    The initContainer will use this configMap to read secrets from an Azure Key Vault and then write the secrets to the users.conf file. The users.conf file contains user account information. In the Key Vault, the secret name should be the username and the secret value should be the password. This Key Vault must exist and contain the secrets prior to deploying this solution.

    When I deployed this solution in my environment, I used an Azure DevOps pipeline to create/manage the Key Vault with Terraform and then deploy the secrets using an inline Powershell script. However, this is beyond the scope of this article, and I will not be covering it here. You will also need to create a Service Principal in your AAD tenant and grant it access to the Key Vault. The Service Principal needs to have at least read access to the Key Vault.

    Before deploying the configMap, you need to fill in values for these variables:

    -
        KEYVAULT="Insert name of Key Vault"
    -    AZ_SPN_ID="Insert service principal Id"
    -    AZ_SPN_PASSWORD="Insert service principal password"
    -    AZ_SPN_TENANT_ID="Insert Az AAD Tenant Id"
    -    AZ_SUBSCRIPTION_ID="Insert Az Subscription Id"
    +
        KEYVAULT="Insert name of Key Vault"
    +    AZ_SPN_ID="Insert service principal Id"
    +    AZ_SPN_PASSWORD="Insert service principal password"
    +    AZ_SPN_TENANT_ID="Insert Az AAD Tenant Id"
    +    AZ_SUBSCRIPTION_ID="Insert Az Subscription Id"
     

    These values pertain to the service principal with read access to the Key Vault. After filling out these variables, you can deploy the configMap using kubectl.

    -
    kubectl create -f configmap.yaml
    +
    kubectl create -f configmap.yaml
     

    You can deploy the PVC using this yaml file:

    -
    apiVersion: v1
    -kind: PersistentVolumeClaim
    -metadata:
    -  name: pvc-ftp-clientdirs
    -spec:
    -  accessModes:
    -    - ReadWriteMany
    -  resources:
    -    requests:
    -      storage: 100Gi
    -  storageClassName: azurefile-csi-nfs
    -

    When creating the persistent volume claim for the deployment, you specify azurefile-csi-nfs as the StorageClass. This will create an NFSv4 share in a premium storage account. The reclaim policy of the storage class ensures that the file share is deleted when the associated Persistent Volume is deleted. Change the reclaim policy to “Retain” if you want the file shares to persist after deleting the PV. Furthermore, the storage class enables the file share to be expandable by modifying the storage request size on the PVC.

    +
    apiVersion: v1
    +kind: PersistentVolumeClaim
    +metadata:
    +  name: pvc-ftp-clientdirs
    +spec:
    +  accessModes:
    +    - ReadWriteMany
    +  resources:
    +    requests:
    +      storage: 100Gi
    +  storageClassName: azurefile-csi-nfs
    +

    When creating the persistent volume claim for the deployment, you specify azurefile-csi-nfs as the StorageClass. This will create an NFSv4 share in a premium storage account. The reclaim policy of the storage class ensures that the file share is deleted when the associated Persistent Volume is deleted. Change the reclaim policy to “Retain” if you want the file shares to persist after deleting the PV. Furthermore, the storage class enables the file share to be expandable by modifying the storage request size on the PVC.

    After deploying the PVC, you can verify its existence by running:

    -
    kubectl get pvc
    +
    kubectl get pvc
     

    You should see output similar to the following (the manifest for the replicaSet is by far the most complicated of all the code referenced here):

    -
    apiVersion: apps/v1
    -kind: Deployment
    -metadata:
    -  labels:
    -    app: sftp
    -  name: sftp
    -spec:
    -  replicas: 2
    -  selector:
    -    matchLabels:
    -      app: sftp
    -  strategy: {}
    -  template:
    -    metadata:
    -      labels:
    -        app: sftp
    -  spec:
    -    initContainer:
    -      enabled: true
    -      name: chmodder
    -      image: mcr.microsoft.com/azure-cli
    -      command:
    -        - /bin/sh
    -        - -c
    -        - "/scripts/init.sh"
    -      volumeMounts:
    -        - name: init-shell-script
    -          mountPath: /scripts
    -    containers:
    -      - name: sftp
    -        image: docker.io/atmoz/sftp:alpine
    -        imagePullPolicy: IfNotPresent
    -        resources:
    -          requests:
    -            memory: "64Mi"
    -            cpu: "250m"
    -          limits:
    -            memory: "128Mi"
    -            cpu: "500m"
    -        livenessProbe:
    -          tcpSocket:
    -            port: 22
    -          initialDelaySeconds: 1
    -          timeoutSeconds: 5
    -          periodSeconds: 10
    -          failureThreshold: 3
    -        readinessProbe:
    -          tcpSocket:
    -            port: 22
    -          initialDelaySeconds: 1
    -          timeoutSeconds: 5
    -          periodSeconds: 10
    -          failureThreshold: 3
    -        volumeMounts:
    -          - name: pvc-ftp-clientdirs
    -            mountPath: /home
    -          - name: sftp
    -            mountPath: /etc/sftp
    -    dnsPolicy: ClusterFirst
    -    restartPolicy: Never
    -    volumes:
    -      - name: pvc-ftp-clientdirs
    -        persistentVolumeClaim:
    -          claimName: pvc-ftp-clientdirs
    -      - name: init-shell-script
    -        configMap:
    -          name: init-shell-script
    -      - name: sftp
    -        emptyDir: {}
    -

    You may need to change the CPU/memory requests and limits. These values worked for me, but your results may vary. You can also add/change the labels as you see fit.

    +
    apiVersion: apps/v1
    +kind: Deployment
    +metadata:
    +  labels:
    +    app: sftp
    +  name: sftp
    +spec:
    +  replicas: 2
    +  selector:
    +    matchLabels:
    +      app: sftp
    +  strategy: {}
    +  template:
    +    metadata:
    +      labels:
    +        app: sftp
    +  spec:
    +    initContainer:
    +      enabled: true
    +      name: chmodder
    +      image: mcr.microsoft.com/azure-cli
    +      command:
    +        - /bin/sh
    +        - -c
    +        - "/scripts/init.sh"
    +      volumeMounts:
    +        - name: init-shell-script
    +          mountPath: /scripts
    +    containers:
    +      - name: sftp
    +        image: docker.io/atmoz/sftp:alpine
    +        imagePullPolicy: IfNotPresent
    +        resources:
    +          requests:
    +            memory: "64Mi"
    +            cpu: "250m"
    +          limits:
    +            memory: "128Mi"
    +            cpu: "500m"
    +        livenessProbe:
    +          tcpSocket:
    +            port: 22
    +          initialDelaySeconds: 1
    +          timeoutSeconds: 5
    +          periodSeconds: 10
    +          failureThreshold: 3
    +        readinessProbe:
    +          tcpSocket:
    +            port: 22
    +          initialDelaySeconds: 1
    +          timeoutSeconds: 5
    +          periodSeconds: 10
    +          failureThreshold: 3
    +        volumeMounts:
    +          - name: pvc-ftp-clientdirs
    +            mountPath: /home
    +          - name: sftp
    +            mountPath: /etc/sftp
    +    dnsPolicy: ClusterFirst
    +    restartPolicy: Never
    +    volumes:
    +      - name: pvc-ftp-clientdirs
    +        persistentVolumeClaim:
    +          claimName: pvc-ftp-clientdirs
    +      - name: init-shell-script
    +        configMap:
    +          name: init-shell-script
    +      - name: sftp
    +        emptyDir: {}
    +

    You may need to change the CPU/memory requests and limits. These values worked for me, but your results may vary. You can also add/change the labels as you see fit.

    This will handle routing traffic to our pods.

    -
    apiVersion: v1
    -kind: Service
    -metadata:
    -  name: sftp-service
    -spec:
    -  selector:
    -    app: sftp
    -  type: LoadBalancer
    -  ports:
    -    - protocol: TCP
    -      port: 22
    -      targetPort: 22
    -

    Users will be connected in a round-robin fashion to the pods. This manifest will create a service of type LoadBalancer. Which will in turn create a new public Azure Load Balancer in the resource group that contains your Azure Kubernetes Service cluster if one does not already exist. If you already have a public load balancer, a new frontend IP address will be added.

    +
    apiVersion: v1
    +kind: Service
    +metadata:
    +  name: sftp-service
    +spec:
    +  selector:
    +    app: sftp
    +  type: LoadBalancer
    +  ports:
    +    - protocol: TCP
    +      port: 22
    +      targetPort: 22
    +

    Users will be connected in a round-robin fashion to the pods. This manifest will create a service of type LoadBalancer. Which will in turn create a new public Azure Load Balancer in the resource group that contains your Azure Kubernetes Service cluster if one does not already exist. If you already have a public load balancer, a new frontend IP address will be added.

    That’s all for now. Please feel free to contact me if you have any questions.

    -
    - - - +
    - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-02-05-kubernetes-pod-eviction/index.html b/public/posts/2022-02-05-kubernetes-pod-eviction/index.html index 33d8e688..11dc7c16 100644 --- a/public/posts/2022-02-05-kubernetes-pod-eviction/index.html +++ b/public/posts/2022-02-05-kubernetes-pod-eviction/index.html @@ -1,115 +1,88 @@ + - - - - - - - + + + Kubernetes Pod Eviction · GeekyRyan + + - - -Kubernetes Pod Eviction - GeekyRyan - - - - - - - - - + - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + - - + + + - - - - - + - + + + - - - - - - - - - - - - + + + + + - - - - - - - - - + + @@ -119,127 +92,144 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Kubernetes Pod Eviction

    - - -
    -
    -
    -

    In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation.

    -

    What is Pod Eviction? - - - - - -

    Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. The most common of which is resource starvation on a node. This is referred to as “node-pressure eviction.”

    -
    NAME       READY   STATUS    RESTARTS   AGE
    -nginx      0/1     Evicted   0          10s
    -

    Eviction Process - - - - - -

    The kubelet process running on the node monitors resources such as CPU, memory, disk space, inodes, etc. When one of these resources reaches a certain consumption level, the kubelet will first attempt to clean up resources by deleting non-running pods and images (in the case of storage starvation). The kubelet will then fail one or more pods on the node to reclaim resources. The class of the pod determines the order in which it does this.

    +

    In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation.

    +

    + What is Pod Eviction? + + + Link to heading + +

    +

    Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. The most common of which is resource starvation on a node. This is referred to as “node-pressure eviction.”

    +
    NAME       READY   STATUS    RESTARTS   AGE
    +nginx      0/1     Evicted   0          10s
    +

    + Eviction Process + + + Link to heading + +

    +

    The kubelet process running on the node monitors resources such as CPU, memory, disk space, inodes, etc. When one of these resources reaches a certain consumption level, the kubelet will first attempt to clean up resources by deleting non-running pods and images (in the case of storage starvation). The kubelet will then fail one or more pods on the node to reclaim resources. The class of the pod determines the order in which it does this.

    Pod Classes

    • Guaranteed: Pods that have requests and limits configured for both CPU and memory
    • @@ -248,292 +238,131 @@

      What is Pod Eviction?

    The kubelet will first evict any “best-effort” pods. If this is not enough, the kubelet will evict any “burstable” pods. Pods within the “guaranteed” class are theoretically safe from eviction.

    During a node-pressure eviction, the kubelet sets the PodPhase for the selected pods to “Failed.” This causes the pods to terminate. If a daemonSet or replicaSet manages the pod, the Kubernetes controller-manager will create new pods on another node.

    -

    Recovery - - - - - -

    Node-pressure eviction is almost always avoidable. We can prevent this type of issue by ensuring that we properly size our clusters and create resource limits for pods.

    +

    + Recovery + + + Link to heading + +

    +

    Node-pressure eviction is almost always avoidable. We can prevent this type of issue by ensuring that we properly size our clusters and create resource limits for pods.

    Resource Requests and Limits:

    • Requests: The minimum amount of resources (CPU/memory) that a container needs to start.
    • Limits: The maximum amount of resources that a container is allowed to use.

    Pod resources and requests can be defined in a pod spec or deployment spec. Below is an example of a pod spec with resource requests and limits defined:

    -
    apiVersion: v1
    -kind: Pod
    -metadata:
    -  name: frontend
    -spec:
    -  containers:
    -
    -  - name: nginx
    -    image: nginx
    -    resources:
    -      requests:
    -        memory: "64Mi"
    -        cpu: "250m"
    -      limits:
    -        memory: "128Mi"
    -        cpu: "500m"
    -

    You will often need to clean up evicted pods manually. If you find that your cluster has a large amount of evicted pods, you can clean them up with the following kubectl commands:

    +
    apiVersion: v1
    +kind: Pod
    +metadata:
    +  name: frontend
    +spec:
    +  containers:
    +
    +  - name: nginx
    +    image: nginx
    +    resources:
    +      requests:
    +        memory: "64Mi"
    +        cpu: "250m"
    +      limits:
    +        memory: "128Mi"
    +        cpu: "500m"
    +

    You will often need to clean up evicted pods manually. If you find that your cluster has a large amount of evicted pods, you can clean them up with the following kubectl commands:

    To see all failed pods in the cluster:

    -
    kubectl get pod --all-namespaces --field-selector=status.phase==Failed
    +
    kubectl get pod --all-namespaces --field-selector=status.phase==Failed
     

    To remove all failed pods in the cluster:

    -
    kubectl delete pod --all-namespaces --field-selector=status.phase==Failed
    +
    kubectl delete pod --all-namespaces --field-selector=status.phase==Failed
     

    I hope this article has been helpful. Please reach out if you have any questions or comments! Also, if you would like to learn more, take a look at the official Kubernetes docs:

    -

    https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/

    +

    https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/

    -
    - +
    - - - - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/index.html b/public/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/index.html index cdc47fcb..eafdebaa 100644 --- a/public/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/index.html +++ b/public/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/index.html @@ -1,115 +1,84 @@ + - - - - - - - + + + Accessing Secrets Securely in Azure DevOps Pipelines · GeekyRyan + + - - -Accessing Secrets Securely in Azure DevOps Pipelines - GeekyRyan - - - - - - - - - + - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - + + + + - - + + + - - - - - + - + + + - - - - - - - - - - - - + + + + + - - - - - - - - - + + @@ -119,441 +88,293 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Accessing Secrets Securely in Azure DevOps Pipelines

    - - -
    -
    -
    -

    This post will cover a secure method for accessing secrets in Azure DevOps pipelines.

    -

    Why Azure Key Vault? - - - - - -

    Azure Key Vault is an Azure cloud service used to securely store secrets, keys, and certificates. A secret can be any string of characters, such as API keys, passwords, URLs, etc. Azure Key Vault encrypts data at rest and in transit using HTTPS. Depending on the type of Key Vault you are using, data at rest is encrypted using software encryption (AES 256) or HSM-backed keys.

    +

    This post will cover a secure method for accessing secrets in Azure DevOps pipelines.

    +

    + Why Azure Key Vault? + + + Link to heading + +

    +

    Azure Key Vault is an Azure cloud service used to securely store secrets, keys, and certificates. A secret can be any string of characters, such as API keys, passwords, URLs, etc. Azure Key Vault encrypts data at rest and in transit using HTTPS. Depending on the type of Key Vault you are using, data at rest is encrypted using software encryption (AES 256) or HSM-backed keys.

    Azure Key Vault also gives us the ability to control access to secrets, keys, and certificates using native Key Vault access policies or the newer option of Azure IAM (RBAC) integration.

    -

    What are Variable Groups? - - - - - -

    It’s all in the name. Variable groups are simply a method of grouping Azure DevOps pipeline variables. If you created a release for an application named MyAwesomeApp, you could create a variable group named myawesomeapp-var-group that could then store all of the variables you reference in the release. It’s simply a method of organizing variables.

    +

    + What are Variable Groups? + + + Link to heading + +

    +

    It’s all in the name. Variable groups are simply a method of grouping Azure DevOps pipeline variables. If you created a release for an application named MyAwesomeApp, you could create a variable group named myawesomeapp-var-group that could then store all of the variables you reference in the release. It’s simply a method of organizing variables.

    You apply permissions to variable groups so that only certain people and pipelines/releases are able to use them.

    You can read more here about variable groups and their usage:

    -

    https://docs.microsoft.com/en-us/azure/devops/pipelines/library/variable-groups?view=azure-devops&tabs=yaml#use-a-variable-group

    -

    Creating a Key Vault and Adding Secrets - - - - - -

    If you already have a Key Vault, skip this section.

    +

    https://docs.microsoft.com/en-us/azure/devops/pipelines/library/variable-groups?view=azure-devops&tabs=yaml#use-a-variable-group

    +

    + Creating a Key Vault and Adding Secrets + + + Link to heading + +

    +

    If you already have a Key Vault, skip this section.

    In this post, we will create a Key Vault using the AzureCLI. To create the Vault and a secret, run these commands:

    -
    # Create a resource group
    -az group create --location <location> --name <resource-group-name>
    -
    -# Create a KeyVault
    -az keyvault create --name <keyvault-name> --resource-group <resource-group-name> --enable-soft-delete
    -
    -# Create some secrets in the Key Vault
    -az keyvault secret set --name username --vault-name <keyvault-name> --value <username>
    -az keyvault secret set --name password --vault-name <keyvault-name> --value <password>
    -az keyvault secret set --name tenantId--vault-name <keyvault-name> --value <tenant id>
    +
    # Create a resource group
    +az group create --location <location> --name <resource-group-name>
    +
    +# Create a KeyVault
    +az keyvault create --name <keyvault-name> --resource-group <resource-group-name> --enable-soft-delete
    +
    +# Create some secrets in the Key Vault
    +az keyvault secret set --name username --vault-name <keyvault-name> --value <username>
    +az keyvault secret set --name password --vault-name <keyvault-name> --value <password>
    +az keyvault secret set --name tenantId--vault-name <keyvault-name> --value <tenant id>
     

    You will need to update the location and resource group name with whatever values you want. You will also need to update the username, password, and your Azure AD tenant ID. The username you choose will need read access to your subscription.

    -

    Creating a Variable Group - - - - - -

    Now we’ll create the variable group in Azure DevOps.

    +

    + Creating a Variable Group + + + Link to heading + +

    +

    Now we’ll create the variable group in Azure DevOps.

    Go to your Azure DevOps project > Pipelines > Library and click “+ Variable Group”:

    -

    +

    Give your variable group a name. Then toggle the switch “Link secrets from an Azure key vault as variables”. Select your Azure Subscription (you may need to authorize DevOps access to the subscription, and then select the Key Vault.

    -

    +

    Now we can add the secrets from the Key Vault to the variable group. Under “Variables”, click the “+ Add” button. Select the checkbox next to any secrets you want to add to the variable group, and then click “Ok”.

    -

    +

    Finally, click the “Save” button. You now have a variable group with secrets linked to a Key Vault. Notice the name of the secret is the only thing visible from the variable group. If you were to update the secret value in the Key Vault, Azure DevOps would automatically pick up the new value.

    -

    Use the Variable Group in a Pipeline - - - - - -

    Now that we have our variable group in place, let’s use it in a pipeline. In Azure DevOps, go to Pipelines and click “New pipeline”.

    -

    +

    + Use the Variable Group in a Pipeline + + + Link to heading + +

    +

    Now that we have our variable group in place, let’s use it in a pipeline. In Azure DevOps, go to Pipelines and click “New pipeline”.

    +

    Choose “Azure Repos Git” > “< your git repo> “, “Starter Pipeline”, and then paste in the following code (You will need to update the ‘azureSubscription’ field with your SPN):

    -
    trigger:
    -- main
    -
    -pool:
    -  vmImage: ubuntu-latest
    -
    -variables:
    -  - group: kv-secrets
    -
    -pr: none
    -
    -stages:
    -  - stage: print_resource_groups
    -    jobs:
    -    - job: print_resource_groups
    -      continueOnError: false
    -      steps:
    -        - task: AzureCLI@2
    -          inputs:
    -            azureSubscription: '<Your SPN>'
    -            scriptType: 'bash'
    -            scriptLocation: 'inlineScript'
    -            inlineScript: |
    -              az login --service-principal --username  $(username) --password $(password) --tenant $(tenantId)
    -              az group list              
    -

    Now click “Save and Run”, and then “Save and Run” again.

    -

    +
    trigger:
    +- main
    +
    +pool:
    +  vmImage: ubuntu-latest
    +
    +variables:
    +  - group: kv-secrets
    +
    +pr: none
    +
    +stages:
    +  - stage: print_resource_groups
    +    jobs:
    +    - job: print_resource_groups
    +      continueOnError: false
    +      steps:
    +        - task: AzureCLI@2
    +          inputs:
    +            azureSubscription: '<Your SPN>'
    +            scriptType: 'bash'
    +            scriptLocation: 'inlineScript'
    +            inlineScript: |
    +              az login --service-principal --username  $(username) --password $(password) --tenant $(tenantId)
    +              az group list              
    +

    Now click “Save and Run”, and then “Save and Run” again.

    +

    Once the pipeline finishes running, you can see that it was able to read the subscription and create a list of all resource groups found.

    This is a simple example of using Key Vault credentials in a pipeline. But you can imagine how useful this could be in more complex scenarios.

    That’s all for now. If you have any questions, feel free to reach out!

    -
    - - - +
    - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-03-01-kubernetes-storage-simplified/index.html b/public/posts/2022-03-01-kubernetes-storage-simplified/index.html index 384fffd1..82c732ee 100644 --- a/public/posts/2022-03-01-kubernetes-storage-simplified/index.html +++ b/public/posts/2022-03-01-kubernetes-storage-simplified/index.html @@ -1,115 +1,88 @@ + - - - - - - - + + + Kubernetes Storage Simplified · GeekyRyan + + - - -Kubernetes Storage Simplified - GeekyRyan - - - - - - + - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + - - + + + - - - - - + - + + + - - - - - - - + + + - - - + + + + - - - - - - - - - @@ -117,158 +90,164 @@ - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Kubernetes Storage Simplified

    - - -
    -
    -
    -

    In this blog post, we will attempt to explain the current storage options that exist in Kubernetes. If you are new to Kubernetes, learning about its capabilities of managing the application state can be a daunting task.

    +

    In this blog post, we will attempt to explain the current storage options that exist in Kubernetes. If you are new to Kubernetes, learning about its capabilities of managing the application state can be a daunting task.

    Container images are built-in layers, with the runtime layer being writable. However, any files on this writable layer are only available for the container’s lifetime. We can mount a volume to a directory inside the container to have persistent data.

    Kubernetes storage uses the concepts of volumes. Ephemeral volumes are called volumes and only last the lifetime of a pod, and “persistent volumes” are used for long-term storage. A typical use case for Ephemeral volumes is storing logs that are not sent to stdout.

    Mounting a persistent volume inside a container allows you to persist the state of your application long after the container is terminated. Persistent volumes can also take advantage of the typical storage idiosyncrasies such as backup, compression, and encryption.

    -

    Persistent Volumes - - - - - -

    Kubernetes has several types of persistent volumes. At its core, a persistent volume is simply a directory mounted inside a pod. How that volume is created, the configuration options and the medium that backs it are all determined by the type of volume created.

    +

    + Persistent Volumes + + + Link to heading + +

    +

    Kubernetes has several types of persistent volumes. At its core, a persistent volume is simply a directory mounted inside a pod. How that volume is created, the configuration options and the medium that backs it are all determined by the type of volume created.

    There are several types of volumes available, too many to list here. You may commonly see some volume types: NFS, iSCSI, hostpath, and local. If your Kubernetes cluster exists in a cloud environment such as Azure or AWS, other volume types are available to you (azureDisk, azureFile, and awsElasticBlockStore, respectively). A complete list of types can be found here:

    -

    https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes

    +

    https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes

    Creating a persistent volume is generally a simple task. The first step is determining the type of volume to create. In this post, we will cover creating a local volume. A local volume represents a disk, partition, or directory shared from a node. Local volumes are subject to the availability of the underlying node, meaning that if the node is offline, the volume is also offline and will not be accessible by any pod. Because of this, local volumes should not be used in production.

    A persistent volume can only be created using a declarative approach. To create a persistent local volume, use the following YAML definition:

    -
    apiVersion: v1
    -kind: PersistentVolume
    -metadata:
    -  name: example-pv
    -spec:
    -  capacity:
    -    storage: 100Gi
    -  volumeMode: Filesystem
    -  accessModes:
    -  - ReadWriteOnce
    -  persistentVolumeReclaimPolicy: Delete
    -  storageClassName: local-storage
    -  local:
    -    # the path to the volume or directory on the node
    -    path: /mnt/disks/ssd1
    -  nodeAffinity:
    -    required:
    -      nodeSelectorTerms:
    -      - matchExpressions:
    -        - key: kubernetes.io/hostname
    -          operator: In
    -          values:
    -            # name of the node sharing the volume
    -          - node01
    -

    When creating a persistent volume of this type, you must specify a node affinity. This ensures that the Kubernetes scheduler schedules any pods requesting access to this volume on the correct node. For example, any pod requesting access to the persistent volume named ‘example-PV will only be scheduled on the node ‘node01’.

    +
    apiVersion: v1
    +kind: PersistentVolume
    +metadata:
    +  name: example-pv
    +spec:
    +  capacity:
    +    storage: 100Gi
    +  volumeMode: Filesystem
    +  accessModes:
    +  - ReadWriteOnce
    +  persistentVolumeReclaimPolicy: Delete
    +  storageClassName: local-storage
    +  local:
    +    # the path to the volume or directory on the node
    +    path: /mnt/disks/ssd1
    +  nodeAffinity:
    +    required:
    +      nodeSelectorTerms:
    +      - matchExpressions:
    +        - key: kubernetes.io/hostname
    +          operator: In
    +          values:
    +            # name of the node sharing the volume
    +          - node01
    +

    When creating a persistent volume of this type, you must specify a node affinity. This ensures that the Kubernetes scheduler schedules any pods requesting access to this volume on the correct node. For example, any pod requesting access to the persistent volume named ‘example-PV will only be scheduled on the node ‘node01’.

    Let’s dive into this persistent volume spec a bit more:

    You can change the capacity of the persistent volume by updating:

    -
    spec:
    -  capacity:
    -    storage: 100Gi
    -

    The accessModes will be determined by the storage provider being used. There are generally 3 access modes available: ReadWriteOnce, ReadWriteMany, and ReadOnlyMany.

    +
    spec:
    +  capacity:
    +    storage: 100Gi
    +

    The accessModes will be determined by the storage provider being used. There are generally 3 access modes available: ReadWriteOnce, ReadWriteMany, and ReadOnlyMany.

    • ReadWriteOnce – The volume can be mounted as read-write by a single node
    • ReadWriteMany – The volume can be mounted as read-write by many nodes
    • @@ -282,25 +261,26 @@

      Persistent Volumes

    Currently, only NFS and hostPath volumes support recycling. Cloud storage providers (Azure, AWS, and GCE) support deletion.

    The other aspects of this spec are unique to the volume being used. Since we are using a local volume here, we must specify the path to the directory or volume on the host and the host which is sharing the directory or volume:

    -
      local:
    -    # the path to the volume or directory on the node
    -    path: /mnt/disks/ssd1
    -  nodeAffinity:
    -    required:
    -      nodeSelectorTerms:
    -      - matchExpressions:
    -        - key: kubernetes.io/hostname
    -          operator: In
    -          values:
    -            # name of the node sharing the volume
    -          - node01
    -

    Ephemeral Volumes - - - - - -

    Note: The Kubernetes documentation recognizes configMaps and Secrets as ephemeral volumes. However, in this article, we will only discuss ephemeral volumes used for data storage (emptyDir volumes).

    +
      local:
    +    # the path to the volume or directory on the node
    +    path: /mnt/disks/ssd1
    +  nodeAffinity:
    +    required:
    +      nodeSelectorTerms:
    +      - matchExpressions:
    +        - key: kubernetes.io/hostname
    +          operator: In
    +          values:
    +            # name of the node sharing the volume
    +          - node01
    +

    + Ephemeral Volumes + + + Link to heading + +

    +

    Note: The Kubernetes documentation recognizes configMaps and Secrets as ephemeral volumes. However, in this article, we will only discuss ephemeral volumes used for data storage (emptyDir volumes).

    Ephemeral volumes are defined within the context of a pod. This means that you cannot create an ephemeral volume on its own. Instead, define the ephemeral volume in the pod or a deployment spec.

    Ephemeral volumes are useful in a few scenarios:

      @@ -310,355 +290,205 @@

      Persistent Volumes

    If one of the containers in the pod happens to restart, data on the ephemeral volume will still exist; as long as one of the containers is mounting, it stays online. In other words, if a pod mounting the ephemeral volume is removed from a node, data on the ephemeral volume is lost. However, if a pod crashes, the data on the volume remains intact.

    As stated previously, creating an ephemeral volume is done as part of the pod or deployment template:

    -
    apiVersion: v1
    -kind: Pod
    -metadata:
    -  name: test-pd
    -spec:
    -  containers:
    -  - image: k8s.gcr.io/test-webserver
    -    name: test-container
    -    volumeMounts:
    -    - mountPath: /cache
    -      name: cache-volume
    -  volumes:
    -  - name: cache-volume
    -    emptyDir: {}
    -

    If the template, you add a volume of type ’emptyDir’ in the ‘volumes’ spec and name it. You can mount this volume in any container in the pod. The volume does not have to be mounted to the same directory in each container.

    -

    Persistent Volume Claims - - - - - -

    A persistentVolumeClaim (often referred to as a ‘PVC’) is used by a pod to create a ‘claim’ on storage. Using a PVC, a pod can mount multiple persistent volumes simultaneously to any directory in the pod.

    +
    apiVersion: v1
    +kind: Pod
    +metadata:
    +  name: test-pd
    +spec:
    +  containers:
    +  - image: k8s.gcr.io/test-webserver
    +    name: test-container
    +    volumeMounts:
    +    - mountPath: /cache
    +      name: cache-volume
    +  volumes:
    +  - name: cache-volume
    +    emptyDir: {}
    +

    If the template, you add a volume of type ’emptyDir’ in the ‘volumes’ spec and name it. You can mount this volume in any container in the pod. The volume does not have to be mounted to the same directory in each container.

    +

    + Persistent Volume Claims + + + Link to heading + +

    +

    A persistentVolumeClaim (often referred to as a ‘PVC’) is used by a pod to create a ‘claim’ on storage. Using a PVC, a pod can mount multiple persistent volumes simultaneously to any directory in the pod.

    PersistentVolumeClaim’s are a Kubernetes primitive that can be deployed from a manifest:

    -
    apiVersion: v1
    -kind: PersistentVolumeClaim
    -metadata:
    -  name: fast-storage-pvc
    -spec:
    -  accessModes:
    -    - ReadWriteMany
    -  volumeMode: Filesystem
    -  resources:
    -    requests:
    -      storage: 8Gi
    -  storageClassName: fast
    -

    Most of the options in the manifest above seem pretty obvious. The volumeMode specifies whether to consume the persistent volume as a FileSystem or block device. The resources section helps specify the amount of storage you require (8Gi in this example). We will cover the storageClassName in the next section. Finally, the accessModes are identical to those described above in the Persistent Volumes section.

    +
    apiVersion: v1
    +kind: PersistentVolumeClaim
    +metadata:
    +  name: fast-storage-pvc
    +spec:
    +  accessModes:
    +    - ReadWriteMany
    +  volumeMode: Filesystem
    +  resources:
    +    requests:
    +      storage: 8Gi
    +  storageClassName: fast
    +

    Most of the options in the manifest above seem pretty obvious. The volumeMode specifies whether to consume the persistent volume as a FileSystem or block device. The resources section helps specify the amount of storage you require (8Gi in this example). We will cover the storageClassName in the next section. Finally, the accessModes are identical to those described above in the Persistent Volumes section.

    Pods access a volume by using the persistentVolumeClaim as volume. Claims must exist in the same namespace as the pod using the claim. The controller finds the claim in the pods’ namespace and uses it to find a persistent volume capable of backing the claim. The volume is then mounted on the host and attached to the pod.

    To create a pod that utilizes a PVC, use the following yaml definition:

    -
    apiVersion: v1
    -kind: Pod
    -metadata:
    -  name: test-pd
    -spec:
    -  containers:
    -  - image: k8s.gcr.io/test-webserver
    -    name: test-container
    -    volumeMounts:
    -    - mountPath: /mnt/share
    -      name: azfileshare
    -  volumes:
    -  - name: cache-volume
    -    persistentVolumeClaim:
    -      claimName: azfileshare
    -

    Storage Classes - - - - - -

    In this article, we will only be referencing Kubernetes storage classes with respect to dynamic provisioners. If you would like to learn more, please reference the Kubernetes docs:

    -

    https://bit.ly/3ruJD2A

    +
    apiVersion: v1
    +kind: Pod
    +metadata:
    +  name: test-pd
    +spec:
    +  containers:
    +  - image: k8s.gcr.io/test-webserver
    +    name: test-container
    +    volumeMounts:
    +    - mountPath: /mnt/share
    +      name: azfileshare
    +  volumes:
    +  - name: cache-volume
    +    persistentVolumeClaim:
    +      claimName: azfileshare
    +

    + Storage Classes + + + Link to heading + +

    +

    In this article, we will only be referencing Kubernetes storage classes with respect to dynamic provisioners. If you would like to learn more, please reference the Kubernetes docs:

    +

    https://bit.ly/3ruJD2A

    Storage Classes have many uses. Kubernetes is unopinionated about what a storage class represents. They can be used to represent different characteristics of storage (performance, compression method, file system modes, etc.). Storage Classes can also be used to provision persistent volumes dynamically, which will be the focus of this article.

    Storage classes are often packaged with CSI drivers. Each StorageClass contains the fields “provisioner”, “parameters”, and “reclaimPolicy”. The provisioner field is used to determine what CSI driver is used for provisioning volumes.

    This is an example of the storage class packaged with the AzureFiles CSI driver:

    -
    kind: StorageClass
    -apiVersion: storage.k8s.io/v1
    -metadata:
    -  name: azurefileshare
    -provisioner: file.csi.azure.com # replace with "kubernetes.io/azure-file" if aks version is less than 1.21
    -mountOptions:
    -  - dir_mode=0777
    -  - file_mode=0777
    -  - uid=0
    -  - gid=0
    -  - mfsymlinks
    -  - cache=strict
    -  - actimeo=30
    -parameters:
    -  skuName: Standard_LRS
    -

    You can see in the above manifest that the provisioner is set to ‘file.csi.azure.com.’ When a pod uses a PVC in its manifest that references this storage class, the provisioner will dynamically manage the underlying storage.

    +
    kind: StorageClass
    +apiVersion: storage.k8s.io/v1
    +metadata:
    +  name: azurefileshare
    +provisioner: file.csi.azure.com # replace with "kubernetes.io/azure-file" if aks version is less than 1.21
    +mountOptions:
    +  - dir_mode=0777
    +  - file_mode=0777
    +  - uid=0
    +  - gid=0
    +  - mfsymlinks
    +  - cache=strict
    +  - actimeo=30
    +parameters:
    +  skuName: Standard_LRS
    +

    You can see in the above manifest that the provisioner is set to ‘file.csi.azure.com.’ When a pod uses a PVC in its manifest that references this storage class, the provisioner will dynamically manage the underlying storage.

    The name of the storageClass is referenced in the persistentVolumeClaim:

    -
    apiVersion: v1
    -kind: PersistentVolumeClaim
    -metadata:
    -  name: azfileshare
    -spec:
    -  accessModes:
    -    - ReadWriteMany
    -  resources:
    -    requests:
    -      storage: 8Gi
    -  storageClassName: azurefileshare
    -

    You could then reference this PVC in a pod:

    -
    apiVersion: v1
    -kind: Pod
    -metadata:
    -  name: test-pd
    -spec:
    -  containers:
    -  - image: k8s.gcr.io/test-webserver
    -    name: test-container
    -    volumeMounts:
    -    - mountPath: /mnt/share
    -      name: azfileshare
    -  volumes:
    -  - name: cache-volume
    -    persistentVolumeClaim:
    -      claimName: azfileshare
    -

    That concludes this article. I know that is a lot of information! As always, if you have any questions or comments, please reach out.

    - -
    +
    apiVersion: v1
    +kind: PersistentVolumeClaim
    +metadata:
    +  name: azfileshare
    +spec:
    +  accessModes:
    +    - ReadWriteMany
    +  resources:
    +    requests:
    +      storage: 8Gi
    +  storageClassName: azurefileshare
    +

    You could then reference this PVC in a pod:

    +
    apiVersion: v1
    +kind: Pod
    +metadata:
    +  name: test-pd
    +spec:
    +  containers:
    +  - image: k8s.gcr.io/test-webserver
    +    name: test-container
    +    volumeMounts:
    +    - mountPath: /mnt/share
    +      name: azfileshare
    +  volumes:
    +  - name: cache-volume
    +    persistentVolumeClaim:
    +      claimName: azfileshare
    +

    That concludes this article. I know that is a lot of information! As always, if you have any questions or comments, please reach out.

    + + + + +
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-04-30-injecting-multiple-kubernetes-volumes-to-the-same-directory-in-a-pod/index.html b/public/posts/2022-04-30-injecting-multiple-kubernetes-volumes-to-the-same-directory-in-a-pod/index.html index 9129ac0c..0371c1d7 100644 --- a/public/posts/2022-04-30-injecting-multiple-kubernetes-volumes-to-the-same-directory-in-a-pod/index.html +++ b/public/posts/2022-04-30-injecting-multiple-kubernetes-volumes-to-the-same-directory-in-a-pod/index.html @@ -1,563 +1,394 @@ + - - - - - - - + + + Injecting multiple Kubernetes volumes to the same directory in a pod · GeekyRyan + + - - -Injecting multiple Kubernetes volumes to the same directory in a pod - GeekyRyan - - - - - - + - - - - - - + + + - + + + + + + + + + + + + - - - - - - - - + + + + - + + + - + - - - + + - - - + + + + - - - - - - + + + + - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - -
    -
    - - - -
    -
    -
    -

    Injecting multiple Kubernetes volumes to the same directory in a pod

    - - -
    -
    -
    -

    We can inject configuration into containers using Kubernetes config maps and secrets. These objects can be consumed by a pod as environment variables, command-line arguments, or as configuration files mounted in a volume. For the subject of this article, we will focus on mounting multiple config maps/secrets into a single directory on a pod.

    -

    Mounting a configmap or secret in a Volume is relatively straightforward (for anyone familiar with Kubernetes primitives). Take for example the following deployment definition:

    -
    kind: ConfigMap
    -apiVersion: v1
    -metadata:
    -  name: hello-world-config
    -data:
    -  application.properties: |
    -    greeting=Hello
    -    name=World    
    -
    ----
    -
    -kind: Secret
    -apiVersion: v1
    -metadata:
    -  name: hello-world-credentials
    -data:
    -  credentials.properties: <base64 goes here>
    -type: Opaque
    -
    ----
    -
    -kind: Deployment
    -apiVersion: apps/v1
    -metadata:
    -  name: hello-world
    -spec:
    -  replicas: 1
    -  selector:
    -    matchLabels:
    -      app: hello-world
    -  template:
    -    metadata:
    -      labels:
    -        app: hello-world
    -    spec:
    -      containers:
    -        - name: hello-world
    -          image: busybox:latest
    -          command:
    -            - /bin/sh
    -            - -c
    -            - sleep 5000
    -          volumeMounts:
    -            - name: hello-world-config-volume
    -              mountPath: /config/application.properties
    -              readOnly: true
    -            - name: hello-world-credentials-volume
    -              mountPath: /config/credentials.properties
    -              readOnly: true
    -      volumes:
    -        - name: hello-world-config-volume
    -          configMap:
    -            name: hello-world-config
    -        - name: hello-world-credentials-volume
    -          secret:
    -            secretName: hello-world-credentials
    -

    When this deployment is created, we see two directories are created in this pod (one for the configMap, and one for the secret). How can we mount these as two files in the ‘config’ directory, rather than two individual directories?

    -

    -

    The ~VolumeMounts~ directive within the container spec of the deployment has an optional (less-known) parameter named ‘subPath’. By using this parameter, we can mount a configMap and secret in the same directory within a pod.

    -

    Let’s focus on the following deployment spec:

    -
    kind: ConfigMap
    -apiVersion: v1
    -metadata:
    -  name: hello-world-config
    -data:
    -  application.properties: |
    -    greeting=Hello
    -    name=World    
    -
    ----
    -
    -kind: Secret
    -apiVersion: v1
    -metadata:
    -  name: hello-world-credentials
    -data:
    -  credentials.properties: <base64 goes here>
    -type: Opaque
    -
    ----
    -
    -kind: Deployment
    -apiVersion: apps/v1
    -metadata:
    -  name: hello-world
    -spec:
    -  replicas: 1
    -  selector:
    -    matchLabels:
    -      app: hello-world
    -  template:
    -    metadata:
    -      labels:
    -        app: hello-world
    -    spec:
    -      containers:
    -        - name: hello-world
    -          image: busybox:latest
    -          command:
    -            - /bin/sh
    -            - -c
    -            - sleep 5000
    -          volumeMounts:
    -            - name: hello-world-config-volume
    -              mountPath: /config/application.properties
    -              subPath: application.properties
    -              readOnly: true
    -            - name: hello-world-credentials-volume
    -              mountPath: /config/credentials.properties
    -              subPath: credentials.properties
    -              readOnly: true
    -      volumes:
    -        - name: hello-world-config-volume
    -          configMap:
    -            name: hello-world-config
    -        - name: hello-world-credentials-volume
    -          secret:
    -            secretName: hello-world-credentials
    -

    Now, if we deploy this, we can see that we have two files in the ‘config’ directory of the pod, rather than a subdirectory for each config/secret:

    -

    -

    In this example, the key application.properties from the configuration map will be mounted to a file with the same name under /config/, and the secret value credentials.properties will be mounted to a second file under that directory. Both files will be read-only to the application.

    - -
    - - - - - - +
    - - - + - - - - - - +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/index.html b/public/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/index.html index e94dbccf..6d85d43e 100644 --- a/public/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/index.html +++ b/public/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/index.html @@ -1,540 +1,364 @@ + - - - - - - - + + + Remove Kubernetes Namespace Stuck in the Terminating State · GeekyRyan + + - - -Remove Kubernetes Namespace Stuck in the Terminating State - GeekyRyan - - - - - - + - - - - - - + + + - + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + - + + + - + - - - + + - - - + + + + - - - - - - + + + + - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Remove Kubernetes Namespace Stuck in the Terminating State

    - - -
    -
    -
    -

    In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state.

    +

    In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state.

    A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. One day, you decide you no longer want this blog, so you plan to delete it. Rather than tediously deleting all of the various entities associated with this blog, you can delete the namespace that contains these entities. This will essentially ‘cascade delete’ the resources within the namespace as well.

    After deleting the namespace for your blog, you notice that it still exists, but the state of it is ‘Terminating’, and it has been like this for a long time (hours or maybe even days).

    -

    +

    Kubernetes will occassionally fail to delete third-party resources when deleting a namespace, causing the namespace to linger. This can happen if the third-party API managing the resource is not responding to requests. To verify if any of these resources still exist, use this command:

    kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get --show-kind --show-all --ignore-not-found -n <terminating-namespace>
     

    If you happen to see any resources in the output, you can try force deleting them and then try to delete the namespace again.

    In my experience, the majority of the time you will not find any resources still hanging around. Rather, the namespace will be completely empty. What is going on here?

    Let’s take a look at the namespace:

    -
    $ kubectl get namespace darn-c101 -o yaml
    -
    apiVersion: v1
    -kind: Namespace
    -metadata:
    -  annotations:
    -	kubectl.kubernetes.io/last-applied-configuration: |
    -	kubernetes.io/metadata.name: darn-c101
    -spec:
    -  finalizers:
    -  - kubernetes
    -status:
    -  conditions:
    - - lastTransitionTime: "2022-06-01T19:05:31Z"
    -	message: 'Some content in the namespace has finalizers remaining: darn-c101.geekyryan.io/finalizer in 1 resource instances'
    -	reason: SomeFinalizersRemain
    -	status: "True"
    -	type: NamespaceFinalizersRemaining
    -  phase: Terminating
    -

    Notice the inclusion of the finalizers field in the above JSON. Some namespaces have a finalizer defined under spec.

    +
    $ kubectl get namespace darn-c101 -o yaml
    +
    apiVersion: v1
    +kind: Namespace
    +metadata:
    +  annotations:
    +	kubectl.kubernetes.io/last-applied-configuration: |
    +	kubernetes.io/metadata.name: darn-c101
    +spec:
    +  finalizers:
    +  - kubernetes
    +status:
    +  conditions:
    + - lastTransitionTime: "2022-06-01T19:05:31Z"
    +	message: 'Some content in the namespace has finalizers remaining: darn-c101.geekyryan.io/finalizer in 1 resource instances'
    +	reason: SomeFinalizersRemain
    +	status: "True"
    +	type: NamespaceFinalizersRemaining
    +  phase: Terminating
    +

    Notice the inclusion of the finalizers field in the above JSON. Some namespaces have a finalizer defined under spec.

    A finalizer is a special metadata key that tells Kubernetes to wait until a specific condition is met before it fully deletes a resource. Much like a finalizer in the .NET framework (does Java have those too? 😀 )

    So when you run a command like kubectl delete namespace <namespace>, Kubernetes checks for a finalizer in the metadata.finalizers field. If the resource defined in the finalizer cannot be deleted, then the namespace is not deleted either. This puts the namespace into a perpetual terminating state and is never actually deleted.

    When an object has been terminating for an excessive time, check its finalizers by inspecting the metadata.finalizers field in its YAML.

    So we now know what the problem is. How can we solve it? Well, it’s actually quite simple. If you are using bash, use this script:

    -
    #!/bin/bash
    -
    -namespaces=$(kubectl get ns --field-selector=status.phase==Terminating -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}')
    -
    -if [ -z "$namespaces"]
    -then
    -  echo "No namespaces to delete."
    -  exit
    -else
    -  for namespace in $namespaces
    -  do
    -    echo "[Removing Namespace]: $namespace"
    -    kubectl get namespace $namespace -o json | tr -d "\n" | sed "s/\"finalizers\": \[[^]]\+\]/\"finalizers\": []/" | kubectl replace --raw /api/v1/namespaces/$namespace/finalize -f - > /dev/null 2>&1
    -  done
    -fi
    -

    Delete Terminating Kubernetes Namespaces with Bash (github.com)

    +
    #!/bin/bash
    +
    +namespaces=$(kubectl get ns --field-selector=status.phase==Terminating -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}')
    +
    +if [ -z "$namespaces"]
    +then
    +  echo "No namespaces to delete."
    +  exit
    +else
    +  for namespace in $namespaces
    +  do
    +    echo "[Removing Namespace]: $namespace"
    +    kubectl get namespace $namespace -o json | tr -d "\n" | sed "s/\"finalizers\": \[[^]]\+\]/\"finalizers\": []/" | kubectl replace --raw /api/v1/namespaces/$namespace/finalize -f - > /dev/null 2>&1
    +  done
    +fi
    +

    Delete Terminating Kubernetes Namespaces with Bash (github.com)

    It will search for any namespace that is stuck in the terminating state and forcefully remove it by removing the finalizers field and then using kubectl replace to commit the change back to the Kube API.

    If you prefer Powershell, you can use this script:

    -
    $terminatingNamespaces = kubectl get ns --field-selector=status.phase==Terminating -o jsonpath="{range .items[*]}{.metadata.name}{'\n'}{end}"
    -
    -foreach ($ns in $terminatingNamespaces) {
    -    Write-Verbose '[FOUND]: Forcefully removing $ns'
    -    $jsonObj = kubectl get namespace $ns -o json | ConvertFrom-Json | foreach-object { $_.spec.finalizers = @(); $_ } |
    -    convertto-json | kubectl replace --raw /api/v1/namespaces/$namespace/finalize -f -
    -}
    -

    Delete Terminating Kubernetes Namespaces with Powershell (github.com)

    +
    $terminatingNamespaces = kubectl get ns --field-selector=status.phase==Terminating -o jsonpath="{range .items[*]}{.metadata.name}{'\n'}{end}"
    +
    +foreach ($ns in $terminatingNamespaces) {
    +    Write-Verbose '[FOUND]: Forcefully removing $ns'
    +    $jsonObj = kubectl get namespace $ns -o json | ConvertFrom-Json | foreach-object { $_.spec.finalizers = @(); $_ } |
    +    convertto-json | kubectl replace --raw /api/v1/namespaces/$namespace/finalize -f -
    +}
    +

    Delete Terminating Kubernetes Namespaces with Powershell (github.com)

    It does the same thing as the bash script, just in more of a Window-zy way.

    It’s that simple. I hope this was helpful. If you have any questions, comments, or concerns, please feel free to reach out.

    -
    - + - - - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/index.html b/public/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/index.html index 33290984..9de092c0 100644 --- a/public/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/index.html +++ b/public/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/index.html @@ -1,482 +1,314 @@ + - - - - - - - + + + EF Core &#8211; Unable to create an object of type DbContext · GeekyRyan + + - + -EF Core &#8211; Unable to create an object of type DbContext - GeekyRyan + + + + + + + - - - - - - - - + + + + + + + + + + + + + - + + + + - - - - - + + + - - - + - + + + - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    EF Core &#8211; Unable to create an object of type DbContext

    - - -
    -
    -
    -

    This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it!

    +

    This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it!

    When running EF Core migrations in a solution, you may come across this error:

    -

    +

    There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio.

    To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’.

    -

    +

    If you are using clean architecture, or some other architecture that has your startup context and your dbContext in different projects, you will need to set your startup project to your runtime, and the ‘Default Project’ in the package manager console to the project containing your dbContext.

    -

    - -
    - +

    - + - - -
    - - - - - - - + + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-06-26-running-docker-in-wsl-v1/index.html b/public/posts/2022-06-26-running-docker-in-wsl-v1/index.html index c9afc3a4..a30a7f57 100644 --- a/public/posts/2022-06-26-running-docker-in-wsl-v1/index.html +++ b/public/posts/2022-06-26-running-docker-in-wsl-v1/index.html @@ -1,511 +1,333 @@ + - - - - - - - + + + Running Docker in WSL v1 · GeekyRyan + + - - -Running Docker in WSL v1 - GeekyRyan - - - - - - + - - - - - - + + + - + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + - + + + - + - - - + + - - - + + + + - - - - - - + + + + - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Running Docker in WSL v1

    - - -
    -
    -
    -

    I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate.

    +

    I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate.

    Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. I receive this nice message:

    -
    $ docker
    -
    -The command 'docker' could not be found in this WSL 1 distro.
    -We recommend to convert this distro to WSL 2 and activate
    -the WSL integration in Docker Desktop settings.
    -
    -See https://docs.docker.com/docker-for-windows/wsl/ for details.
    +
    $ docker
    +
    +The command 'docker' could not be found in this WSL 1 distro.
    +We recommend to convert this distro to WSL 2 and activate
    +the WSL integration in Docker Desktop settings.
    +
    +See https://docs.docker.com/docker-for-windows/wsl/ for details.
     

    So I’m in somewhat of a catch-22 here…

    To work around this problem until a proper solution is found, I was able to get Docker working with WSL v1.

    If you happen to be having a similar issue (and it seems like quite a few people are, considering the number of Github posts I found), just follow these steps:

    • Expose the Docker daemon in docker desktop settings:
    -

    +

    Install the stand-alone Docker client in WSL v1:

    -
    $ wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.5.tgz
    -$ tar zxvf docker-20.10.5.tgz
    -$ cd docker
    +
    $ wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.5.tgz
    +$ tar zxvf docker-20.10.5.tgz
    +$ cd docker
     

    Set the default Docker daemon in WSL v1:

    -
    export DOCKER_HOST=tcp://localhost:2375
    +
    export DOCKER_HOST=tcp://localhost:2375
     

    Verify you can connect to Docker running on Windows from within WSL:

    -
    ./docker info
    +
    ./docker info
     

    This is also beneficial in that you only have one Docker host to manage your containers, network, etc., rather than two.

    -
    - +
    - - - - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/index.html b/public/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/index.html index 82ee63bf..f8fc30be 100644 --- a/public/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/index.html +++ b/public/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/index.html @@ -1,507 +1,326 @@ + - - - - - - - + + + Scheduled Kubernetes Worker Node Maintenance with Kured · GeekyRyan + + - - -Scheduled Kubernetes Worker Node Maintenance with Kured - GeekyRyan - - - - - - + - - - - - - + + + - + + + + + + + + + + + + + + + + - - - - - - - - + + + + - + + + - + - - - + + - - - + + + + - - - - - - + + + + - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Scheduled Kubernetes Worker Node Maintenance with Kured

    - - -
    -
    -
    -

    If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this?

    +

    If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this?

    Weaveworks created a great tool for simplifying these steps: Kured (the Kubernetes Reboot Daemon). Let’s start by deploying Kured to our cluster.

    Kured can be deployed in one of several ways. In this article, we’ll focus on deploying it via Helm. This is the simplest and quickest way to get it running in our cluster.

    Follow these steps to install the Helm chart:

    -
    # 1) Add the Kured Helm repository
    -helm repo add kured https://weaveworks.github.io/kured
    -
    -# 2) Update your local Helm chart repository cache
    -helm repo update
    -
    -# 3) Create a dedicated namespace where you would like to deploy kured
    -kubectl create namespace kured
    -
    -# 4) Install kured in that namespace with Helm 3 (only on Linux nodes)
    -helm install kured kured/kured --namespace kured --set nodeSelector."kubernetes\.io/os"=linux
    +
    # 1) Add the Kured Helm repository
    +helm repo add kured https://weaveworks.github.io/kured
    +
    +# 2) Update your local Helm chart repository cache
    +helm repo update
    +
    +# 3) Create a dedicated namespace where you would like to deploy kured
    +kubectl create namespace kured
    +
    +# 4) Install kured in that namespace with Helm 3 (only on Linux nodes)
    +helm install kured kured/kured --namespace kured --set nodeSelector."kubernetes\.io/os"=linux
     

    If all went well with the command above, that’s it, you’re done! Have a nice day! 🙂

    If you want to test Kured, login to one of your Linux nodes, and install some patches with your package manager of choice (any patch that requires a reboot, typically patches that modify kernel headers). Then, check for a file named ‘reboot-required’ in /var/run:

    -
    ls -lisa /var/run/reboot-required
    +
    ls -lisa /var/run/reboot-required
     

    If you installed patches, and this file does not exist, none of your patches require a reboot. We can still fake the system into thinking a reboot is required by manually creating the ‘reboot-required’ file:

    -
    sudo touch /var/run/reboot-required
    -

    +
    sudo touch /var/run/reboot-required
    +

    Then, we’ll use Kubetail to tail the logs of all our Kured pods:

    -
    kubetail -label kured --namespace kured
    -

    +
    kubetail -label kured --namespace kured
    +

    By default, Kured checks for the existence of the sentinel file every 60 minutes. However, this behavior can be changed. See the github repo for more info:

    -

    weaveworks/kured: Kubernetes Reboot Daemon

    +

    weaveworks/kured: Kubernetes Reboot Daemon

    Scheduling on the node should be disabled if you are within the Kured schedule

    -

    +

    Now that the node is cordoned off, running pods on the node are drained, and the node is rebooted.

    That’s it for this article. Have a great day!

    -
    - +
    - - - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-07-19-aks-scale-down-mode/index.html b/public/posts/2022-07-19-aks-scale-down-mode/index.html index 6573a16f..1ca6cd6c 100644 --- a/public/posts/2022-07-19-aks-scale-down-mode/index.html +++ b/public/posts/2022-07-19-aks-scale-down-mode/index.html @@ -1,493 +1,313 @@ + - - - - - - - + + + AKS Scale Down Mode · GeekyRyan + + - - -AKS Scale Down Mode - GeekyRyan - - - - - - + - - - - - - + + + - + + + + + + + + + + + + + + + + - - - - - - - - + + + + - + + + - + - - - + + - - - + + + + - - - - - - + + + + - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    AKS Scale Down Mode

    - - -
    -
    -
    -

    By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete or deallocate nodes.

    +

    By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete or deallocate nodes.

    Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. However, you will still need to pay for any storage that the node is using. Having persistent storage also means that any container images that were cached on the node will still be there when the node starts back up. This can be a major performance benefit if you are using Windows containers because the images for these containers are typically very large.

    Scale down mode can be configured in several ways. Here, we will look at configuring it via the Azure CLI and Terraform.

    Azure CLI:

    -
    az aks nodepool update --scale-down-mode Deallocate --name nplinux01 --cluster-name myAKSCluster --resource-group myResourceGroup
    +
    az aks nodepool update --scale-down-mode Deallocate --name nplinux01 --cluster-name myAKSCluster --resource-group myResourceGroup
     

    Terraform:

    -
    resource "azurerm_kubernetes_cluster_node_pool" "nodepool" {
    -  name                  = "nplinux01"
    -  kubernetes_cluster_id = azurerm_kubernetes_cluster.example.id
    -  vm_size               = "Standard_DS2_v2"
    -  node_count            = 2
    -  scale_down_mode       = "Deallocate"
    -
    -  tags = {
    -    Environment = "lab"
    -  }
    -}
    +
    resource "azurerm_kubernetes_cluster_node_pool" "nodepool" {
    +  name                  = "nplinux01"
    +  kubernetes_cluster_id = azurerm_kubernetes_cluster.example.id
    +  vm_size               = "Standard_DS2_v2"
    +  node_count            = 2
    +  scale_down_mode       = "Deallocate"
    +
    +  tags = {
    +    Environment = "lab"
    +  }
    +}
     

    At the time of this writing, Terraform does not support configuring scale-down mode for the default AKS node pool. Node pools using ephemeral disks do not support ‘deallocate’ mode

    -
    - +
    - - - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-07-21-reading-json-files-with-go/index.html b/public/posts/2022-07-21-reading-json-files-with-go/index.html index 7ee9aa09..22ca7a5c 100644 --- a/public/posts/2022-07-21-reading-json-files-with-go/index.html +++ b/public/posts/2022-07-21-reading-json-files-with-go/index.html @@ -1,115 +1,87 @@ + - - - - - - - + + + Reading Json Files with Go · GeekyRyan + + - - -Reading Json Files with Go - GeekyRyan - - - - - - + - - - - + + + - + + + + + + + + + + + + + + + + + - - - - - + - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - - - + + + + + - - - - - - - - - + + @@ -119,441 +91,306 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Reading Json Files with Go

    - - -
    -
    -
    -

    JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting +

    JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting with it, and most public APIs accept JSON in HTTP requests.

    In this post, we’ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the JSON data within the file into a memory structure.

    Let’s assume we have the following JSON data representing an employee:

    -
    {
    -  "Id": 1,
    -  "firstName": "Steve",
    -  "lastName": "Rogers",
    -  "alias": "Captain America",
    -  "Department": "Avengers"
    -}
    +
    {
    +  "Id": 1,
    +  "firstName": "Steve",
    +  "lastName": "Rogers",
    +  "alias": "Captain America",
    +  "Department": "Avengers"
    +}
     

    We need a way of representing this data in memory when decoding it from JSON. For this, we will need to create a struct:

    We will build up our go module as we progress through the article

    Let’s start:

    -
    // main.go
    -package main
    -
    -import (
    -	"encoding/json"
    -	"fmt"
    -	"io/ioutil"
    -	"log"
    -)
    -
    -// Hero represents an hero
    -// ALL fields must be exportable! Otherwise the JSON parsing will fail.
    -type Hero struct {
    -	Id        int
    -	FirstName string
    -	LastName  string
    -	Alias     string
    -	Group     string
    -}
    -
    -func main() {
    -
    -	// Here we set the log prefix. When reading stack traces, this makes it easier to know
    -	// where a failure occurred.
    -	log.SetPrefix("main(): ")
    -
    -	// We first need to load the JSON file into memory
    -	content, err := ioutil.ReadFile("./heros.json")
    -	if err != nil {
    -		log.Fatal("Error opening the file: ", err)
    -	}
    -
    -	// Now we parse the JSON data into a memory structure. We know our JSON file will have more than one hero object,
    -  // so we'll use make() to create a []Hero slice. Since go is a pass-by-value language, we will then use the address-of
    -  // operator (&) to unmarshal our json data into the heros slice
    -	heros := make([]Hero, 5)
    -	err = json.Unmarshal(content, &heros)
    -	if err != nil {
    -		log.Fatal("Error occurred during unmarshal: ", err)
    -	}
    -
    -	// now we can read/interact with the data. We'll loop over the array
    -  // and print the values in memory
    -	for i := 0; i < len(heros); i++ {
    -		fmt.Println(heros[i].Id)
    -		fmt.Println(heros[i].FirstName)
    -		fmt.Println(heros[i].LastName)
    -		fmt.Println(heros[i].Group)
    -	}
    -}
    +
    // main.go
    +package main
    +
    +import (
    +	"encoding/json"
    +	"fmt"
    +	"io/ioutil"
    +	"log"
    +)
    +
    +// Hero represents an hero
    +// ALL fields must be exportable! Otherwise the JSON parsing will fail.
    +type Hero struct {
    +	Id        int
    +	FirstName string
    +	LastName  string
    +	Alias     string
    +	Group     string
    +}
    +
    +func main() {
    +
    +	// Here we set the log prefix. When reading stack traces, this makes it easier to know
    +	// where a failure occurred.
    +	log.SetPrefix("main(): ")
    +
    +	// We first need to load the JSON file into memory
    +	content, err := ioutil.ReadFile("./heros.json")
    +	if err != nil {
    +		log.Fatal("Error opening the file: ", err)
    +	}
    +
    +	// Now we parse the JSON data into a memory structure. We know our JSON file will have more than one hero object,
    +  // so we'll use make() to create a []Hero slice. Since go is a pass-by-value language, we will then use the address-of
    +  // operator (&) to unmarshal our json data into the heros slice
    +	heros := make([]Hero, 5)
    +	err = json.Unmarshal(content, &heros)
    +	if err != nil {
    +		log.Fatal("Error occurred during unmarshal: ", err)
    +	}
    +
    +	// now we can read/interact with the data. We'll loop over the array
    +  // and print the values in memory
    +	for i := 0; i < len(heros); i++ {
    +		fmt.Println(heros[i].Id)
    +		fmt.Println(heros[i].FirstName)
    +		fmt.Println(heros[i].LastName)
    +		fmt.Println(heros[i].Group)
    +	}
    +}
     

    Create a file named employees.json with similar data:

    -
    [
    -  {
    -    "Id": 1,
    -    "firstName": "Steve",
    -    "lastName": "Rogers",
    -    "alias": "Captain America",
    -    "group": "Avengers"
    -  },
    -  {
    -    "Id": 2,
    -    "firstName": "Clark",
    -    "lastName": "Kent",
    -    "alias": "Superman",
    -    "group": "Justice League"
    -  }
    -]
    +
    [
    +  {
    +    "Id": 1,
    +    "firstName": "Steve",
    +    "lastName": "Rogers",
    +    "alias": "Captain America",
    +    "group": "Avengers"
    +  },
    +  {
    +    "Id": 2,
    +    "firstName": "Clark",
    +    "lastName": "Kent",
    +    "alias": "Superman",
    +    "group": "Justice League"
    +  }
    +]
     

    Now, we can run our main.go file:

    -
    11:40:47 ryan@xerxes json → go run main.go
    -1
    -Steve
    -Rogers
    -Avengers
    -2
    -Clark
    -Kent
    -Justice League
    -11:40:49 ryan@xerxes json
    +
    11:40:47 ryan@xerxes json → go run main.go
    +1
    +Steve
    +Rogers
    +Avengers
    +2
    +Clark
    +Kent
    +Justice League
    +11:40:49 ryan@xerxes json
     

    Pretty simple! That’s why I love go. We accomplished all of this with ~50 lines of code. Doing something similar in asp.net project would easily double that count and involve creating multiple files! (nothing against asp.net or c#, I think c# is a great language and use it daily)

    Now, ‘go’ try this!

    -
    - - - +
    - - -
    - - - - - - - + + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-08-04-querying-rest-with-powershell/index.html b/public/posts/2022-08-04-querying-rest-with-powershell/index.html index 1d5d4204..f48ecf54 100644 --- a/public/posts/2022-08-04-querying-rest-with-powershell/index.html +++ b/public/posts/2022-08-04-querying-rest-with-powershell/index.html @@ -1,115 +1,88 @@ + - - - - - - - + + + Powershell for Devops - Querying REST APIs with Powershell · GeekyRyan + + - - -Powershell for Devops - Querying REST APIs with Powershell - GeekyRyan - - - - - - + - - - - + + + - + + + + + + + + + + + + + + + + + + - - - - - + - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - - - + + + + + - - - - - - - - - + + @@ -119,413 +92,272 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Powershell for Devops - Querying REST APIs with Powershell

    - - -
    -
    -
    -

    This will be a short post on querying REST APIs with Powershell.

    +

    This will be a short post on querying REST APIs with Powershell.

    It’s hard to argue that REST APIs are the predominant technology for interacting with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) product without having to go through the exercise of a more complicated integration. REST APIs communicate in a common format, typically JSON. However, most will allow us to choose the response format by specifying an option in the ‘Accept’ header. Most languages provide a native method for interacting with REST APIs. This objective for this post is to show you how simple this is with Powershell.

    -

    To get started, we’ll need a public API to interact with. I’m going to use https://icanhazdadjoke.com/, because +

    To get started, we’ll need a public API to interact with. I’m going to use https://icanhazdadjoke.com/, because there is no authentication and no rate-limiting (two concepts we will cover in another post).

    Calling the API is extremely simple:

    -
    $url = "https://icanhazdadjoke.com/"
    -
    -Invoke-RestMethod -Uri $url -Method Get
    +
    $url = "https://icanhazdadjoke.com/"
    +
    +Invoke-RestMethod -Uri $url -Method Get
     

    However, this results in the content being returned as plain text. This isn’t ideal.

    Let’s pass the ‘Accept’ header to tell the API the format we are expecting to be returned:

    -
    $url = "https://icanhazdadjoke.com/"
    -$headers = @{
    -    'Accept' = 'application/json'
    -}
    -Invoke-RestMethod -Uri $url -Method Get -Headers $headers
    +
    $url = "https://icanhazdadjoke.com/"
    +$headers = @{
    +    'Accept' = 'application/json'
    +}
    +Invoke-RestMethod -Uri $url -Method Get -Headers $headers
     

    Output:

    -
    [15:04:34] C:\..\..\rnemeth90.github.io on main   +1    Invoke-RestMethod -Uri $url -Method Get -Headers $headers
    -
    -id          joke                                                  status
    ---          ----                                                  ------
    -3LmyXvsPfqc I don't trust stairs. They're always up to something.    200
    +
    [15:04:34] C:\..\..\rnemeth90.github.io on main   +1    Invoke-RestMethod -Uri $url -Method Get -Headers $headers
    +
    +id          joke                                                  status
    +--          ----                                                  ------
    +3LmyXvsPfqc I don't trust stairs. They're always up to something.    200
     

    That looks a little better. For those of you familiar with Powershell, the output above probably looks completely normal. But for those not-so-familiar with Powershell, or those expecting more of a ‘json-esk’ output, this may look a bit… weird.

    Powershell is an object oriented language. Everything is an object in Powershell, even the response of this request. What you see in the output is simply the properties of the object.

    Luckily Powershell provides us with a cmdlet to convert an object into json (aptly named: ConvertTo-Json). We can use it like this:

    -
    $url = "https://icanhazdadjoke.com/"
    -$headers = @{
    -    'Accept' = 'application/json'
    -}
    -Invoke-RestMethod -Uri $url -Method Get -Headers $headers | ConvertTo-Json
    +
    $url = "https://icanhazdadjoke.com/"
    +$headers = @{
    +    'Accept' = 'application/json'
    +}
    +Invoke-RestMethod -Uri $url -Method Get -Headers $headers | ConvertTo-Json
     

    Here we are piping the output from Invoke-RestMethod to ConvertTo-Json. Pretty neat!

    Output:

    -
    [15:04:35] C:\..\..\rnemeth90.github.io on main   +1    Invoke-RestMethod -Uri $url -Method Get -Headers $headers | Convertto-json
    -{
    -  "id": "AAdFBXnGlyd",
    -  "joke": "If you walk into a forest and cut down a tree, but the tree doesn't understand why you cut it down, do you think it's stumped?",
    -  "status": 200
    -}
    +
    [15:04:35] C:\..\..\rnemeth90.github.io on main   +1    Invoke-RestMethod -Uri $url -Method Get -Headers $headers | Convertto-json
    +{
    +  "id": "AAdFBXnGlyd",
    +  "joke": "If you walk into a forest and cut down a tree, but the tree doesn't understand why you cut it down, do you think it's stumped?",
    +  "status": 200
    +}
     

    Now, that looks more normal.

    There is much more we can do with Invoke-RestMethod. The ‘Method’ parameter of this cmdlet accepts any of the common HTTP methods (GET, PUT, PATCH, DELETE, POST, HEAD). You can also specify other headers and a body (using the -body parameter).

    Both of these parameters accept dictionaries:

    -
    $url = "https://icanhazdadjoke.com/"
    -$headers = @{
    -    'Accept' = 'application/json'
    -    'Host' = 'MyServer'
    -}
    -$body = @{
    -    'Eat' = 'Pizza'
    -}
    -Invoke-RestMethod -Uri $url -Method Get -Headers $headers -Body $body | ConvertTo-Json
    +
    $url = "https://icanhazdadjoke.com/"
    +$headers = @{
    +    'Accept' = 'application/json'
    +    'Host' = 'MyServer'
    +}
    +$body = @{
    +    'Eat' = 'Pizza'
    +}
    +Invoke-RestMethod -Uri $url -Method Get -Headers $headers -Body $body | ConvertTo-Json
     

    Unfortunately I won’t be able to show the other HTTP methods, as this API only supports GET requests. So that’s all for now.

    -
    - - - +
    - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-09-06-go-mod-replace-copy/index.html b/public/posts/2022-09-06-go-mod-replace-copy/index.html index 333320fd..1e281dcb 100644 --- a/public/posts/2022-09-06-go-mod-replace-copy/index.html +++ b/public/posts/2022-09-06-go-mod-replace-copy/index.html @@ -1,249 +1,227 @@ + - - - - - - - + + + Use “replace” in go.mod to Point to a Local Module · GeekyRyan + + - + -Use “replace” in go.mod to Point to a Local Module - GeekyRyan + + + + + + + - - - - - - - - + + + + + + + + + + + + + - + + + + - - - - - + + + - - - + - + + + - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Use “replace” in go.mod to Point to a Local Module

    - - -
    -
    -
    -

    If you want to the local version of a dependency in Go rather than one in a remote repository, use the replace keyword.

    +

    If you want to the local version of a dependency in Go rather than one in a remote repository, use the replace keyword.

    The replace line goes above your require statements, like so:

    -
    
    -    module github.com/rnemeth90/foo
    -
    -    replace github.com/rnemeth90/bar => /Users/rnemeth90/Projects/bar
    -
    -    require (
    -    	github.com/rnemeth90/bar v1.0.0
    -    )
    +
    
    +    module github.com/rnemeth90/foo
    +
    +    replace github.com/rnemeth90/bar => /Users/rnemeth90/Projects/bar
    +
    +    require (
    +    	github.com/rnemeth90/bar v1.0.0
    +    )
     

    Now when you compile this module go build or go install, it will use your local code rather than the remote dependency.

    According to the docs, you do need to make sure that the code you’re pointing to also has a go.mod file:

    Note: if the right-hand side of a replace directive is a filesystem path, then the target must have a go.mod file at that location. If the go.mod file is not present, you can create one with go mod init.

    -

    https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive

    +

    https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive

    You can also create this line from the command line using the go mod edit command.

    $ go mod edit -replace github.com/rnemeth90/bar=/Users/rnemeth90/Projects/bar
    @@ -251,245 +229,93 @@ 

    Use “replace” in go.mod to Point to a Local Mo

    Following the -replace is first what you want to replace, then an equals sign, then what you’re replacing it with.

    Hopefully this helps someone who was stuck with this like me 🙂

    -

    - - - +
    - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-09-12-update-azure-devops-spn-secret/index.html b/public/posts/2022-09-12-update-azure-devops-spn-secret/index.html index 273cfd3c..80558ab7 100644 --- a/public/posts/2022-09-12-update-azure-devops-spn-secret/index.html +++ b/public/posts/2022-09-12-update-azure-devops-spn-secret/index.html @@ -1,118 +1,88 @@ + - - - - - - - + + + Update Azure Devops SPN Secret · GeekyRyan + + - - -Update Azure Devops SPN Secret - GeekyRyan - - - - - - + - - - - + + + - + + + + + + + + + + + + + + + - - - - - - - - - + + + + - - - - + + + - - - - - + - + + + - - - - - - - - - - - - + + + + + - - - - - - - - - + + @@ -122,119 +92,125 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Update Azure Devops SPN Secret

    - - -
    -
    -
    -

    If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal.

    +

    If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal.

    In this article, I’ll show you two methods for updating a secret for a service principal prior to expiration.

    -

    Update the secret via the Azure Devops Portal: - - - - - -

      +

      + Update the secret via the Azure Devops Portal: + + + Link to heading + +

      +
      • Go to “Service Connections” in the Azure Devops portal
      • Find the SPN you want to update, then click “Manage Service Principal”
      • Then on the service principal page, click Certificates & Secrets
      • @@ -247,247 +223,93 @@

        Update the secret via th
      • You can now remove whatever you added to the description.
      -
    - - - + - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/index.html b/public/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/index.html index 3f5d10a2..3306e02e 100644 --- a/public/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/index.html +++ b/public/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/index.html @@ -1,521 +1,340 @@ + - - - - - - - + + + Chaining YAML Pipelines in Azure Devops · GeekyRyan + + - - -Chaining YAML Pipelines in Azure Devops - GeekyRyan - - - - - - + - - - - - - + + + - + + + + + + + + + + + + + + + - - - - - - - - + + + + - + + + - + - - - + + - - - + + + + - - - - - - + + + + - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Chaining YAML Pipelines in Azure Devops

    - - -
    -
    -
    -

    In this article, we’ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. +

    In this article, we’ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to figure this out.

    Our two pipelines will exist in the same repository. We have a dependent-pipeline, that we only want to run once the source-pipeline is finished. This is useful if you have some infrastructure you want to build, prior to deploying something to that infrastructure.

    The process is actually quite simple. First, let’s define our source pipeline:

    -
    # source-pipeline
    -
    -trigger:
    -- main
    -
    -pool:
    -  vmImage: ubuntu-latest
    -
    -steps:
    -- script: echo Hello, world!
    -  displayName: 'Run a  one-line script'
    -
    -- script: |
    -    echo Add other tasks to build, test, and deploy your project.
    -    echo See https://aka.ms/yaml    
    -  displayName: 'Run a multi-line  script'
    -

    Nothing fancy here, just the build in template pipeline that Microsoft gives us for free when we create a “Starter Pipeline”.

    +
    # source-pipeline
    +
    +trigger:
    +- main
    +
    +pool:
    +  vmImage: ubuntu-latest
    +
    +steps:
    +- script: echo Hello, world!
    +  displayName: 'Run a  one-line script'
    +
    +- script: |
    +    echo Add other tasks to build, test, and deploy your project.
    +    echo See https://aka.ms/yaml    
    +  displayName: 'Run a multi-line  script'
    +

    Nothing fancy here, just the build in template pipeline that Microsoft gives us for free when we create a “Starter Pipeline”.

    Now, let’s create another pipeline in the same repo that will be triggered when the pipeline above completes:

    -
    # dependent-pipeline
    -
    -trigger:
    -- none # we want this pipeline to be triggered manually, not based on PR, etc.
    -
    -pool:
    -  vmImage: ubuntu-latest
    -
    -resources:
    -  pipelines:
    -    - pipeline: source-pipeline #this can be anything
    -      source: 'source-pipeline' #this needs to be the name of the 'source' pipeline
    -      trigger: true # Run dependent-pipeline pipeline when any run of security-lib-ci completes
    -
    -steps:
    -- script: echo Hello, world!
    -  displayName: 'Run a one-line script'
    -
    -- script: |
    -    echo Add other tasks to build, test, and deploy your project.
    -    echo See https://aka.ms/yaml    
    -  displayName: 'Run a multi-line script'
    -

    The resources block above defines our dependency. You want to be sure to configure the trigger of the dependent pipeline appropriately as well.

    +
    # dependent-pipeline
    +
    +trigger:
    +- none # we want this pipeline to be triggered manually, not based on PR, etc.
    +
    +pool:
    +  vmImage: ubuntu-latest
    +
    +resources:
    +  pipelines:
    +    - pipeline: source-pipeline #this can be anything
    +      source: 'source-pipeline' #this needs to be the name of the 'source' pipeline
    +      trigger: true # Run dependent-pipeline pipeline when any run of security-lib-ci completes
    +
    +steps:
    +- script: echo Hello, world!
    +  displayName: 'Run a one-line script'
    +
    +- script: |
    +    echo Add other tasks to build, test, and deploy your project.
    +    echo See https://aka.ms/yaml    
    +  displayName: 'Run a multi-line script'
    +

    The resources block above defines our dependency. You want to be sure to configure the trigger of the dependent pipeline appropriately as well.

    There are several options for fine-tuning this process. See the office Microsoft documentation below:

    -

    Link to the Microsoft Docs

    +

    Link to the Microsoft Docs

    -
    - + - - - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-12-24-gh-actions-copy/index.html b/public/posts/2022-12-24-gh-actions-copy/index.html index 80cc9e53..521f15a8 100644 --- a/public/posts/2022-12-24-gh-actions-copy/index.html +++ b/public/posts/2022-12-24-gh-actions-copy/index.html @@ -1,565 +1,386 @@ + - - - - - - - + + + Building a Golang App with Github Actions · GeekyRyan + + - - -Building a Golang App with Github Actions - GeekyRyan - - - - - - + - - - - - - + + + - + + + + + + + + + + + + + + + - - - - - - - - + + + + - + + + - + - - - + + - - - + + + + - - - - - - + + + + - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Building a Golang App with Github Actions

    - - -
    -
    -
    -

    In this article, we’ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app +

    In this article, we’ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app written in any language though. We’ll cover the following:

    1. What are github actions?
    2. Setting up the workflow to build, test, and deploy a binary
    -

    Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. They are powerful and I suggest you read more at the Official Docs

    -

    To get started, we’ll need a golang app to build. You can use my example here if you do not have your own.

    +

    Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. They are powerful and I suggest you read more at the Official Docs

    +

    To get started, we’ll need a golang app to build. You can use my example here if you do not have your own.

    The process is relatively simple. At the root of your repo, create the following directories:

    -
    mkdir -p .github/workflows
    +
    mkdir -p .github/workflows
     

    Then create a yaml file (you can name it anything you want) with the content below:

    -
    name: build-release-binary
    -
    -run-name: Create Github Release for GoLang binary
    -
    -# anytime we push to our repo with a tag starting with the
    -# letter 'r', we run the build
    -on:
    -  push:
    -    tags:
    -    - 'r*'
    -
    -jobs:
    -  build:
    -    runs-on: ubuntu-22.04
    -    permissions:
    -      contents: write
    -    steps:
    -    # checkout our github repo to the build agent
    -    - uses: actions/checkout@v3
    -      with:
    -        fetch-depth: 0 # get all tags, needed to get git log
    -        ref: main
    -
    -    # Setup the Go environment
    -    - name: setup Go Lang
    -      id: build
    -      uses: actions/setup-go@v3
    -      with:
    -        go-version: '^1.19.2'
    -
    -    # Build our application
    -    - run: |
    -        go version
    -        cd src
    -        if [ ! -e *.mod ]; then
    -          go mod init ${GITHUB_REPOSITORY}
    -        fi
    -        go mod tidy
    -        go build -ldflags "-X main.Version=${GITHUB_REF_NAME} -X main.BuiltBy=github-actions" main.go
    -        execFile=$(find . -type f -executable)        
    -
    -    # Output more values for debugging
    -    - run: git version
    -    - run: git branch
    -    - run: git tag
    -
    -    # tag our release
    -    - name: get semantic tag version and release notes from commit messages
    -      id: tag
    -      run: |
    -        currentTag=${GITHUB_REF_NAME}
    -        major_minor=$(echo "$currentTag" | cut -d'.' -f1-2)
    -        patch=$(echo "$currentTag" | cut -d'.' -f3)
    -        # avoid empty patch number
    -        [ -n "$patch" ] && ((patch--)) || patch=".x"
    -        previousTag="${major_minor}.${patch}"
    -
    -        echo "" > body.log
    -        if git tag | grep $previousTag ; then
    -          git log -q ${currentTag}...${previousTag} --pretty="- %s" -q --no-color >> body.log
    -        else
    -          git log --pretty="- %s" -q --no-color >> body.log
    -        fi
    -        line_count=$(cat body.log | wc -l)
    -
    -        echo "currentTag=$currentTag" >> $GITHUB_OUTPUT
    -        echo "previousTag=$previousTag" >> $GITHUB_OUTPUT
    -        echo "line_count=$line_count" >> $GITHUB_OUTPUT        
    -
    -    #  create Github release with release note from file and binary asset attached
    -    - uses: ncipollo/release-action@v1
    -      with:
    -        name: ${{ env.GITHUB_REF_NAME }}
    -        tag: ${{ env.GITHUB_REF_NAME }}
    -        artifacts: "src/main"
    -        bodyFile: "body.log"
    -        token: ${{ secrets.GITHUB_TOKEN }}
    -

    Each step within this workflow starts with a hyphen. The steps are well-commented, so I will not explain them further. Once you have this file in your repo, push it to github. Then navigate to the Actions tab in your repository and you should see your workflow on the left hand side of the screen.

    -

    -

    Now that we have our workflow setup, to get it run, all you need to do is tag and push your release to github. To do that, you can run the script in my repo create_new_gh_release.sh or simply run the following commands (be sure to change the tag as needed):

    -
    newtag=r1.0.0
    -git tag $newtag && git push origin $newtag
    +
    name: build-release-binary
    +
    +run-name: Create Github Release for GoLang binary
    +
    +# anytime we push to our repo with a tag starting with the
    +# letter 'r', we run the build
    +on:
    +  push:
    +    tags:
    +    - 'r*'
    +
    +jobs:
    +  build:
    +    runs-on: ubuntu-22.04
    +    permissions:
    +      contents: write
    +    steps:
    +    # checkout our github repo to the build agent
    +    - uses: actions/checkout@v3
    +      with:
    +        fetch-depth: 0 # get all tags, needed to get git log
    +        ref: main
    +
    +    # Setup the Go environment
    +    - name: setup Go Lang
    +      id: build
    +      uses: actions/setup-go@v3
    +      with:
    +        go-version: '^1.19.2'
    +
    +    # Build our application
    +    - run: |
    +        go version
    +        cd src
    +        if [ ! -e *.mod ]; then
    +          go mod init ${GITHUB_REPOSITORY}
    +        fi
    +        go mod tidy
    +        go build -ldflags "-X main.Version=${GITHUB_REF_NAME} -X main.BuiltBy=github-actions" main.go
    +        execFile=$(find . -type f -executable)        
    +
    +    # Output more values for debugging
    +    - run: git version
    +    - run: git branch
    +    - run: git tag
    +
    +    # tag our release
    +    - name: get semantic tag version and release notes from commit messages
    +      id: tag
    +      run: |
    +        currentTag=${GITHUB_REF_NAME}
    +        major_minor=$(echo "$currentTag" | cut -d'.' -f1-2)
    +        patch=$(echo "$currentTag" | cut -d'.' -f3)
    +        # avoid empty patch number
    +        [ -n "$patch" ] && ((patch--)) || patch=".x"
    +        previousTag="${major_minor}.${patch}"
    +
    +        echo "" > body.log
    +        if git tag | grep $previousTag ; then
    +          git log -q ${currentTag}...${previousTag} --pretty="- %s" -q --no-color >> body.log
    +        else
    +          git log --pretty="- %s" -q --no-color >> body.log
    +        fi
    +        line_count=$(cat body.log | wc -l)
    +
    +        echo "currentTag=$currentTag" >> $GITHUB_OUTPUT
    +        echo "previousTag=$previousTag" >> $GITHUB_OUTPUT
    +        echo "line_count=$line_count" >> $GITHUB_OUTPUT        
    +
    +    #  create Github release with release note from file and binary asset attached
    +    - uses: ncipollo/release-action@v1
    +      with:
    +        name: ${{ env.GITHUB_REF_NAME }}
    +        tag: ${{ env.GITHUB_REF_NAME }}
    +        artifacts: "src/main"
    +        bodyFile: "body.log"
    +        token: ${{ secrets.GITHUB_TOKEN }}
    +

    Each step within this workflow starts with a hyphen. The steps are well-commented, so I will not explain them further. Once you have this file in your repo, push it to github. Then navigate to the Actions tab in your repository and you should see your workflow on the left hand side of the screen.

    +

    +

    Now that we have our workflow setup, to get it run, all you need to do is tag and push your release to github. To do that, you can run the script in my repo create_new_gh_release.sh or simply run the following commands (be sure to change the tag as needed):

    +
    newtag=r1.0.0
    +git tag $newtag && git push origin $newtag
     

    Now, go back to the Actions tab in your repo, and you should see the build running. Once it completes, go back to the Code tab in your github repo and you will see the release on the right hand side of the screen.

    -

    +

    -
    - +
    - - - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-12-25-synology-backup-to-cloud/index.html b/public/posts/2022-12-25-synology-backup-to-cloud/index.html index dd3f0c12..e3d8da94 100644 --- a/public/posts/2022-12-25-synology-backup-to-cloud/index.html +++ b/public/posts/2022-12-25-synology-backup-to-cloud/index.html @@ -1,112 +1,81 @@ + - - - - - - - + + + Backup Synology NAS to Azure Storage · GeekyRyan + + - - -Backup Synology NAS to Azure Storage - GeekyRyan - - - - - - - - - + - - - + + + - + + + + + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - - + + + + + + + - - - - - - - - - @@ -115,358 +84,218 @@ - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Backup Synology NAS to Azure Storage

    - - -
    -
    -
    -

    I’m not really a fan of photography. I don’t particularly enjoy the intracies of tuning a high-end DSLR camera. Nor am I a fan of being out in nature to photograph a fall sunrise (though, that does sound peaceful). However, I do take a lot of pictures with my phone (currently, a Pixel 6). Moreso now that I am a new father. I am protective of these photos. So much that I sync them automatically from my phone to two cloud storage providers. I thought the other day, how painful it would be for either of these cloud storage providers to go offline. Though unlikely, anything is possible, right?

    +

    I’m not really a fan of photography. I don’t particularly enjoy the intracies of tuning a high-end DSLR camera. Nor am I a fan of being out in nature to photograph a fall sunrise (though, that does sound peaceful). However, I do take a lot of pictures with my phone (currently, a Pixel 6). Moreso now that I am a new father. I am protective of these photos. So much that I sync them automatically from my phone to two cloud storage providers. I thought the other day, how painful it would be for either of these cloud storage providers to go offline. Though unlikely, anything is possible, right?

    So, like any good engineer, I started looking for a solution for this concern. I have 2 Synology NAS devices here at my home. Calling a Synology a NAS is almost an insult. They are much more than that. Though they specialize in storage, they provide a plethora of apps that extend the functionality of the device. A Synology device can provide storage, email, DNS, media, etc. services though OEM and third-party apps. A single device can also link up with other devices to form a highly-available mesh of Synology services. Pretty neat for just a little black desktop box! Anyway, I’m not a Synology salesman, so let’s get back on track…

    I wanted to be able to have a local copy of all of my photos (and other files) that are currently synced to the cloud. I then wanted to backup this local copy to another remote location (something like a 3-2-1 backup architecture, but not really…). Synology provides an app called Cloud Sync that can be used to sync files from a cloud storage provider like Google Photos/Drive or Microsoft OneDrive to a local device. They also provide another app called Hyper Backup that can be used to backup local files to remote storage, like an Azure Storage Account or Amazon S3 Bucket. By now, you probably get where this is going.

    I’m going to configure Cloud Sync to pull files down to my Synology and then use Hyper Backup to push a weekly backup to Azure Blob Storage. Let’s dive in! If you’re following along, you’ll need to install both of these apps. They are available via One-Click install in the Synology Package Center, so I won’t cover the installation process. The setup is extremely simple as well, but I’ll go over it just because.

    We’ll first setup Cloud Sync. Open Cloud Sync and click the ‘+’ symbol to add a new account.

    For my purposes, I’m going to choose Microsoft OneDrive:

    -

    +

    When prompted to authenticate, login to your OneDrive account. Then, configure the sync settings. You can create a name for the connection, add a local path in which to sync your files to, choose which remote folders/files to sync, the sync direction, a schedule, etc.

    -

    +

    Click Next, and then finish the wizard. Simple.

    Depending on the amount of files you have, you’ll need to allow some time for your files to sync.

    Now, we’ll setup Hyper Backup to backup the files you sync’d locally to remote storage. As stated previously, I’ll be backing up my files to Azure Blob Storage. I have already created the Storage Account in Azure, and will not be covering that in this article.

    Open Hyper Backup and click the ‘+’ symbol in the lower left corner, and then click ‘Data Backup Task’. Then, choose ‘Microsoft Azure’:

    -

    -

    +

    +

    On the next page, enter in your Storage Account info and then click Next. You can then choose which local folders on your Synology to backup:

    -

    +

    Click next and choose to backup application settings:

    -

    +

    On this page, we can configure the backup settings. Name the task, and configure your notification settings, schedule, compression, and encryption.

    -

    +

    On the last page, we configure our backup rotation settings. I am going to keep 31 days of backups, starting from the oldest backup. This means that at any given time I will have 31 days worth of backups in the storage account.

    -

    +

    That’s all for configuring the backups! Very simple. Depending on how much data you have and your ISP, it may take a while to backup your files. If you configured notifications, you should receive a notification once the job is complete.

    -
    - + - - - - -
    - - - - - - - + + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/index.html b/public/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/index.html index 3f57b5ea..79fc0501 100644 --- a/public/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/index.html +++ b/public/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/index.html @@ -1,112 +1,85 @@ + - - - - - - - + + + Handling Graceful Shutdown in a .NET App Hosted in Kubernetes · GeekyRyan + + - - -Handling Graceful Shutdown in a .NET App Hosted in Kubernetes - GeekyRyan - - - - - - - - - + - - - + + + - + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - - - + + + + + - - - - - - - - - + + @@ -116,475 +89,330 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Handling Graceful Shutdown in a .NET App Hosted in Kubernetes

    - - -
    -
    -
    -

    I was recently involved with troubleshooting some API’s hosted in Kubernetes throwing http/502’s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. It was actually a combination of these blogs (and the resolutions posted) that ended up resolving our issue.

    -

    So what was actually causing the 502’s? - - - - - -

    As stated, these APIs are hosted in Kubernetes. They are written primarily in c# (.NET Framework) and hosted in Windows Server Core containers. The pods are load balanced using a service, and we have an Nginx ingress on top of the service. Nothing fancy, just a typical setup that you may have seen or even built yourself. We implement automatic scaling for our replica sets using a standard Kubernetes-native HPA or Keda, depending on the app. We have autoscale rules defined for the pods. Our clusters are hosted in Azure Kubernetes Service, and we autoscale our node pools. So, there are several layers of scaling happening in our clusters at any given time. Occasionally, when a pod was handling a client request, Kubelet or a controller would come along and scale the pod in. We were initially under the belief that the terminationGracePeriodSeconds value within our deployment would allow the pod to continue running for the defined number of seconds. However, we were mistaken. This value tells Kubernetes to allow the application running within the pod some time to clean up. It does not tell the app to continue running for the defined number of seconds after it receives a sigterm signal. This logic actually needs to be implemented within the application itself, or with a prestop hook. The prestop method is well documented, so I will not cover it here.

    +

    I was recently involved with troubleshooting some API’s hosted in Kubernetes throwing http/502’s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. It was actually a combination of these blogs (and the resolutions posted) that ended up resolving our issue.

    +

    + So what was actually causing the 502’s? + + + Link to heading + +

    +

    As stated, these APIs are hosted in Kubernetes. They are written primarily in c# (.NET Framework) and hosted in Windows Server Core containers. The pods are load balanced using a service, and we have an Nginx ingress on top of the service. Nothing fancy, just a typical setup that you may have seen or even built yourself. We implement automatic scaling for our replica sets using a standard Kubernetes-native HPA or Keda, depending on the app. We have autoscale rules defined for the pods. Our clusters are hosted in Azure Kubernetes Service, and we autoscale our node pools. So, there are several layers of scaling happening in our clusters at any given time. Occasionally, when a pod was handling a client request, Kubelet or a controller would come along and scale the pod in. We were initially under the belief that the terminationGracePeriodSeconds value within our deployment would allow the pod to continue running for the defined number of seconds. However, we were mistaken. This value tells Kubernetes to allow the application running within the pod some time to clean up. It does not tell the app to continue running for the defined number of seconds after it receives a sigterm signal. This logic actually needs to be implemented within the application itself, or with a prestop hook. The prestop method is well documented, so I will not cover it here.

    To implement this in a .NET Framework app running in Windows, you need to add this registry key to your container.

    -
    RUN reg add hklm\system\currentcontrolset\control /v WaitToKillServiceTimeout /t REG_SZ /d 60000 /f
    +
    RUN reg add hklm\system\currentcontrolset\control /v WaitToKillServiceTimeout /t REG_SZ /d 60000 /f
     

    This value tells Windows to wait a number of milliseconds before shutting down Normally, Windows only waits for 5 seconds (default) before shutting down any ‘background’ processes. Windows forcibly shuts down processes after this period of time.

    Next, in the startup class, we’ll add the following code. I have added inline comments to explain.

    -
    
    -namespace MyApp.APIConsoleHost
    -{
    -	public class Program
    -	{
    -    /*
    -      Register the SetConsoleCtrlHandler function in kernel32.dll in the
    -      application to capture CTRL_SHUTDOWN_EVENT events for resource reclamation
    -    */
    -		[DllImport("Kernel32")]
    -		public static extern bool SetConsoleCtrlHandler(HandlerRoutine handler, bool add);
    -
    -    // Define a delegate for our handler routine
    -		public delegate bool HandlerRoutine(CtrlTypes ctrlType);
    -
    -		public static volatile ManualResetEvent _exitEvent = new ManualResetEvent(false);
    -
    -		private static HandlerRoutine _handler;
    -
    -
    -    /*
    -      Define the event types that we want to handle when the application receives a SIGTERM
    -          CTRL_C_EVENT = 0,
    -          CTRL_BREAK_EVENT = 1,
    -          CTRL_CLOSE_EVENT = 2,
    -          CTRL_LOGOFF_EVENT = 5,
    -          CTRL_SHUTDOWN_EVENT = 6
    -    */
    -		public enum CtrlTypes
    -		{
    -			CTRL_SHUTDOWN_EVENT = 6
    -		}
    -
    -    /*
    -        Here we are defining how we want to handle the shutdown
    -        We get a timeout value from an env variable named APP_SHUTDOWN_TIMEOUT
    -        If that env variable is not found, we default to 60 seconds.
    -        We then switch on our CtrlTypes enum and handle each value accordingly,
    -        and then return true.
    -    */
    -		public static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
    -		{
    -			var timeout = ConfigurationManager.AppSettings["APP_SHUTDOWN_TIMEOUT"];
    -			if (string.IsNullOrEmpty(timeout)) { timeout = "60"; }
    -			int counter = int.Parse(timeout);
    -
    -			switch (ctrlType)
    -			{
    -				case CtrlTypes.CTRL_SHUTDOWN_EVENT:
    -					Console.WriteLine($"[{DateTime.UtcNow}] CTRL_SHUTDOWN received");
    -					Console.WriteLine($"[{DateTime.UtcNow}] Web Server is stopping in {counter} seconds");
    -
    -					while (counter > 0)
    -					{
    -						Thread.Sleep(TimeSpan.FromSeconds(1));
    -						counter--;
    -					}
    -
    -					_exitEvent.Set();
    -					return true;
    -				default:
    -					return false;
    -			}
    -		}
    -
    -    /*
    -        Our main method is pretty standard. However, we first register a new handler (_handler),
    -        and then pass it to to the SetConsoleCtrlHandler() method we imported from Kernel32.dll.
    -        The only other 'unique' thing is the _exitEvent.WaitOne(); call defined at the bottom of main().
    -        This is necessary so that main does not immediately exit, and wait's for a signal. We defined a
    -        property for this _exitEvent of type ManualResetEvent at the top of this class file.
    -    */
    -		public static void Main(string[] args)
    -		{
    -			_handler += new HandlerRoutine(ConsoleCtrlCheck);
    -			SetConsoleCtrlHandler(_handler, true);
    -
    -      // redacted ....
    -
    -			var startOptions = BuildStartOptions();
    -
    -      // redacted ....
    -
    -      WebApp.Start<SelfHostStartup>(startOptions);
    -
    -			Console.WriteLine("Press CTRL+C to stop it");
    -
    -			_exitEvent.WaitOne();
    -		}
    -
    -		private static StartOptions BuildStartOptions()
    -		{
    -			var startOptions = new StartOptions();
    -
    -      // redacted start options
    -
    -			return startOptions;
    -		}
    -	}
    -}
    +
    
    +namespace MyApp.APIConsoleHost
    +{
    +	public class Program
    +	{
    +    /*
    +      Register the SetConsoleCtrlHandler function in kernel32.dll in the
    +      application to capture CTRL_SHUTDOWN_EVENT events for resource reclamation
    +    */
    +		[DllImport("Kernel32")]
    +		public static extern bool SetConsoleCtrlHandler(HandlerRoutine handler, bool add);
    +
    +    // Define a delegate for our handler routine
    +		public delegate bool HandlerRoutine(CtrlTypes ctrlType);
    +
    +		public static volatile ManualResetEvent _exitEvent = new ManualResetEvent(false);
    +
    +		private static HandlerRoutine _handler;
    +
    +
    +    /*
    +      Define the event types that we want to handle when the application receives a SIGTERM
    +          CTRL_C_EVENT = 0,
    +          CTRL_BREAK_EVENT = 1,
    +          CTRL_CLOSE_EVENT = 2,
    +          CTRL_LOGOFF_EVENT = 5,
    +          CTRL_SHUTDOWN_EVENT = 6
    +    */
    +		public enum CtrlTypes
    +		{
    +			CTRL_SHUTDOWN_EVENT = 6
    +		}
    +
    +    /*
    +        Here we are defining how we want to handle the shutdown
    +        We get a timeout value from an env variable named APP_SHUTDOWN_TIMEOUT
    +        If that env variable is not found, we default to 60 seconds.
    +        We then switch on our CtrlTypes enum and handle each value accordingly,
    +        and then return true.
    +    */
    +		public static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
    +		{
    +			var timeout = ConfigurationManager.AppSettings["APP_SHUTDOWN_TIMEOUT"];
    +			if (string.IsNullOrEmpty(timeout)) { timeout = "60"; }
    +			int counter = int.Parse(timeout);
    +
    +			switch (ctrlType)
    +			{
    +				case CtrlTypes.CTRL_SHUTDOWN_EVENT:
    +					Console.WriteLine($"[{DateTime.UtcNow}] CTRL_SHUTDOWN received");
    +					Console.WriteLine($"[{DateTime.UtcNow}] Web Server is stopping in {counter} seconds");
    +
    +					while (counter > 0)
    +					{
    +						Thread.Sleep(TimeSpan.FromSeconds(1));
    +						counter--;
    +					}
    +
    +					_exitEvent.Set();
    +					return true;
    +				default:
    +					return false;
    +			}
    +		}
    +
    +    /*
    +        Our main method is pretty standard. However, we first register a new handler (_handler),
    +        and then pass it to to the SetConsoleCtrlHandler() method we imported from Kernel32.dll.
    +        The only other 'unique' thing is the _exitEvent.WaitOne(); call defined at the bottom of main().
    +        This is necessary so that main does not immediately exit, and wait's for a signal. We defined a
    +        property for this _exitEvent of type ManualResetEvent at the top of this class file.
    +    */
    +		public static void Main(string[] args)
    +		{
    +			_handler += new HandlerRoutine(ConsoleCtrlCheck);
    +			SetConsoleCtrlHandler(_handler, true);
    +
    +      // redacted ....
    +
    +			var startOptions = BuildStartOptions();
    +
    +      // redacted ....
    +
    +      WebApp.Start<SelfHostStartup>(startOptions);
    +
    +			Console.WriteLine("Press CTRL+C to stop it");
    +
    +			_exitEvent.WaitOne();
    +		}
    +
    +		private static StartOptions BuildStartOptions()
    +		{
    +			var startOptions = new StartOptions();
    +
    +      // redacted start options
    +
    +			return startOptions;
    +		}
    +	}
    +}
     

    To prevent the HandlerRoutine instance from being recycled by the GC before the program exits, the HandlerRoutine must be static (as seen in the above example). This is important because if the handlerroutine is recycled before the application is finished, it will throw an error, as shown here:

    A callback was made on a garbage collected delegate of type 'Program+HandlerRoutine::Invoke'. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called.
     
    -
    - +
    - - - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2023-01-24-golang-strings-not-equal/index.html b/public/posts/2023-01-24-golang-strings-not-equal/index.html index 45698d56..688af77d 100644 --- a/public/posts/2023-01-24-golang-strings-not-equal/index.html +++ b/public/posts/2023-01-24-golang-strings-not-equal/index.html @@ -1,115 +1,85 @@ + - - - - - - - + + + Golang: When Identical Strings are Not Equal · GeekyRyan + + - - -Golang: When Identical Strings are Not Equal - GeekyRyan - - - - - - + - - - - + + + - + + + + + + + + + + + + + + + - - - - - + - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - - - + + + + + - - - - - - - - - + + @@ -119,481 +89,332 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Golang: When Identical Strings are Not Equal

    - - -
    -
    -
    -

    This will be a quick and dirty post, so please forgive any spelling/grammar mistakes.

    +

    This will be a quick and dirty post, so please forgive any spelling/grammar mistakes.

    I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don’t write a ton of code at work (mostly just scripting/pipelines when I do), so I’m constantly working on something like this in my spare time. Anyway, I was writing this app, got everything working like I wanted it to. I then wrote some of the tests and was iterating over them. I noticed the ListTasks test was failing:

    -
    func TestAddTask(t *testing.T) {
    -	task := "test task number 1"
    -
    -	dir, err := os.Getwd()
    -	if err != nil {
    -		t.Fatal(err)
    -	}
    -
    -	cmdPath := filepath.Join(dir, binaryName)
    -
    -	t.Run("AddNewTask", func(t *testing.T) {
    -		cmd := exec.Command(cmdPath, "-add", task)
    -
    -		if err := cmd.Run(); err != nil {
    -			t.Fatal(err)
    -		}
    -	})
    -
    -  // failing test
    -	t.Run("ListTasks", func(t *testing.T) {
    -		cmd := exec.Command(cmdPath, "-list")
    -		out, err := cmd.CombinedOutput()
    -		if err != nil {
    -			t.Fatal(err)
    -		}
    -
    -		expected := fmt.Sprintf("[ ] 1: %s", task)
    -
    -		if strings.Compare(string(out), expected) != 0 {
    -			t.Errorf("got %v, expected %v\n", out, []byte(expected))
    -		}
    -	})
    -}
    +
    func TestAddTask(t *testing.T) {
    +	task := "test task number 1"
    +
    +	dir, err := os.Getwd()
    +	if err != nil {
    +		t.Fatal(err)
    +	}
    +
    +	cmdPath := filepath.Join(dir, binaryName)
    +
    +	t.Run("AddNewTask", func(t *testing.T) {
    +		cmd := exec.Command(cmdPath, "-add", task)
    +
    +		if err := cmd.Run(); err != nil {
    +			t.Fatal(err)
    +		}
    +	})
    +
    +  // failing test
    +	t.Run("ListTasks", func(t *testing.T) {
    +		cmd := exec.Command(cmdPath, "-list")
    +		out, err := cmd.CombinedOutput()
    +		if err != nil {
    +			t.Fatal(err)
    +		}
    +
    +		expected := fmt.Sprintf("[ ] 1: %s", task)
    +
    +		if strings.Compare(string(out), expected) != 0 {
    +			t.Errorf("got %v, expected %v\n", out, []byte(expected))
    +		}
    +	})
    +}
     

    Seems strange, considering the strings appear to be equivalent in the output:

    -
    ryan:todo/  |main U:4 ?:1 ✗|$ go test -v
    -Building tool...
    -using /tmp/.testtodo.json
    -running...
    -=== RUN   TestAddTask
    -=== RUN   TestAddTask/AddNewTask
    -=== RUN   TestAddTask/ListTasks
    -    main_test.go:82: got [ ] 1: test task number 1
    -        , expected [ ] 1: test task number 1
    ---- FAIL: TestAddTask (0.00s)
    -    --- PASS: TestAddTask/AddNewTask (0.00s)
    -    --- FAIL: TestAddTask/ListTasks (0.00s)
    -FAIL
    -cleaning up...
    -exit status 1
    -FAIL    github.com/rnemeth90/todo/cmd/todo      0.105s
    +
    ryan:todo/  |main U:4 ?:1 ✗|$ go test -v
    +Building tool...
    +using /tmp/.testtodo.json
    +running...
    +=== RUN   TestAddTask
    +=== RUN   TestAddTask/AddNewTask
    +=== RUN   TestAddTask/ListTasks
    +    main_test.go:82: got [ ] 1: test task number 1
    +        , expected [ ] 1: test task number 1
    +--- FAIL: TestAddTask (0.00s)
    +    --- PASS: TestAddTask/AddNewTask (0.00s)
    +    --- FAIL: TestAddTask/ListTasks (0.00s)
    +FAIL
    +cleaning up...
    +exit status 1
    +FAIL    github.com/rnemeth90/todo/cmd/todo      0.105s
     

    What could be happening? After banging my head on the desk a few times, a revelation came to me…

    In Go, strings are simply slices of bytes. I decided to print out each string as a byte array:

    -
    ryan:todo/  |main U:4 ?:1 ✗|$ go test -v
    -Building tool...
    -using /tmp/.testtodo.json
    -running...
    -=== RUN   TestAddTask
    -=== RUN   TestAddTask/AddNewTask
    -=== RUN   TestAddTask/ListTasks
    -    main_test.go:80: got [91 32 93 32 49 58 32 116 101 115 116 32 116 97 115 107 32 110 117 109 98 101 114 32 49 32 10 10], expected [91 32 93 32 49 58 32 116 101 115 116 32 116 97 115 107 32 110 117 109 98 101 114 32 49]
    ---- FAIL: TestAddTask (0.00s)
    -    --- PASS: TestAddTask/AddNewTask (0.00s)
    -    --- FAIL: TestAddTask/ListTasks (0.00s)
    -FAIL
    -cleaning up...
    -exit status 1
    -FAIL    github.com/rnemeth90/todo/cmd/todo      0.144s
    +
    ryan:todo/  |main U:4 ?:1 ✗|$ go test -v
    +Building tool...
    +using /tmp/.testtodo.json
    +running...
    +=== RUN   TestAddTask
    +=== RUN   TestAddTask/AddNewTask
    +=== RUN   TestAddTask/ListTasks
    +    main_test.go:80: got [91 32 93 32 49 58 32 116 101 115 116 32 116 97 115 107 32 110 117 109 98 101 114 32 49 32 10 10], expected [91 32 93 32 49 58 32 116 101 115 116 32 116 97 115 107 32 110 117 109 98 101 114 32 49]
    +--- FAIL: TestAddTask (0.00s)
    +    --- PASS: TestAddTask/AddNewTask (0.00s)
    +    --- FAIL: TestAddTask/ListTasks (0.00s)
    +FAIL
    +cleaning up...
    +exit status 1
    +FAIL    github.com/rnemeth90/todo/cmd/todo      0.144s
     

    Let’s take a closer look at the byte arrays from the test output:

    -
    got      [91 32 93 32 49 58 32 116 101 115 116 32 116 97 115 107 32 110 117 109 98 101 114 32 49 32 10 10]
    -expected [91 32 93 32 49 58 32 116 101 115 116 32 116 97 115 107 32 110 117 109 98 101 114 32 49]
    -

    We can see the byte array returned from cmd.CombinedOutput() has some additional bytes in it at the end (32,10,10). What exactly are 32, 10, and 10? To figure this out, I went over to the go playground: https://go.dev/play/.

    +
    got      [91 32 93 32 49 58 32 116 101 115 116 32 116 97 115 107 32 110 117 109 98 101 114 32 49 32 10 10]
    +expected [91 32 93 32 49 58 32 116 101 115 116 32 116 97 115 107 32 110 117 109 98 101 114 32 49]
    +

    We can see the byte array returned from cmd.CombinedOutput() has some additional bytes in it at the end (32,10,10). What exactly are 32, 10, and 10? To figure this out, I went over to the go playground: https://go.dev/play/.

    Let’s see what happens when we create a byte array with a single number and print it out as a string to the console:

    -

    +

    Interesting, we can see that m was output to the console. So what do our mysterious additional characters in our test result represent? Let’s see:

    -

    +

    It’s hard to tell from the output, but if you look in the results pane, you’ll see a space and two new lines. So 32 represents a space, and 10 represents a new line!

    -

    You can play with this code yourself: https://go.dev/play/p/fGUIxJM6KnV

    +

    You can play with this code yourself: https://go.dev/play/p/fGUIxJM6KnV

    Ok, so let’s fix our failing test:

    -
    func TestAddTask(t *testing.T) {
    -	task := "test task number 1"
    -
    -	dir, err := os.Getwd()
    -	if err != nil {
    -		t.Fatal(err)
    -	}
    -
    -	cmdPath := filepath.Join(dir, binaryName)
    -
    -	t.Run("AddNewTask", func(t *testing.T) {
    -		cmd := exec.Command(cmdPath, "-add", task)
    -
    -		if err := cmd.Run(); err != nil {
    -			t.Fatal(err)
    -		}
    -	})
    -
    -	t.Run("ListTasks", func(t *testing.T) {
    -		cmd := exec.Command(cmdPath, "-list")
    -		out, err := cmd.CombinedOutput()
    -		if err != nil {
    -			t.Fatal(err)
    -		}
    -
    -    // add this line
    -		out = []byte(strings.TrimSuffix(string(out), " \n\n"))
    -
    -		expected := fmt.Sprintf("[ ] 1: %s", task)
    -
    -		if strings.Compare(string(out), expected) != 0 {
    -			t.Errorf("got %v, expected %v\n", out, []byte(expected))
    -		}
    -	})
    -}
    +
    func TestAddTask(t *testing.T) {
    +	task := "test task number 1"
    +
    +	dir, err := os.Getwd()
    +	if err != nil {
    +		t.Fatal(err)
    +	}
    +
    +	cmdPath := filepath.Join(dir, binaryName)
    +
    +	t.Run("AddNewTask", func(t *testing.T) {
    +		cmd := exec.Command(cmdPath, "-add", task)
    +
    +		if err := cmd.Run(); err != nil {
    +			t.Fatal(err)
    +		}
    +	})
    +
    +	t.Run("ListTasks", func(t *testing.T) {
    +		cmd := exec.Command(cmdPath, "-list")
    +		out, err := cmd.CombinedOutput()
    +		if err != nil {
    +			t.Fatal(err)
    +		}
    +
    +    // add this line
    +		out = []byte(strings.TrimSuffix(string(out), " \n\n"))
    +
    +		expected := fmt.Sprintf("[ ] 1: %s", task)
    +
    +		if strings.Compare(string(out), expected) != 0 {
    +			t.Errorf("got %v, expected %v\n", out, []byte(expected))
    +		}
    +	})
    +}
     

    The strings package has a TrimSuffix function that is useful for trimming bits off the end of a string. In the code above, you can see that we added out = []byte(strings.TrimSuffix(string(out), " \n\n")), which will trim off the space (character 32) and the two new lines (character 10). Now when we run our integration test, it passes:

    -
    ryan:todo/  |main U:4 ?:1 ✗|$ go test -v
    -Building tool...
    -using /tmp/.testtodo.json
    -running...
    -=== RUN   TestAddTask
    -=== RUN   TestAddTask/AddNewTask
    -=== RUN   TestAddTask/ListTasks
    ---- PASS: TestAddTask (0.00s)
    -    --- PASS: TestAddTask/AddNewTask (0.00s)
    -    --- PASS: TestAddTask/ListTasks (0.00s)
    -PASS
    -cleaning up...
    -ok      github.com/rnemeth90/todo/cmd/todo      0.106s
    +
    ryan:todo/  |main U:4 ?:1 ✗|$ go test -v
    +Building tool...
    +using /tmp/.testtodo.json
    +running...
    +=== RUN   TestAddTask
    +=== RUN   TestAddTask/AddNewTask
    +=== RUN   TestAddTask/ListTasks
    +--- PASS: TestAddTask (0.00s)
    +    --- PASS: TestAddTask/AddNewTask (0.00s)
    +    --- PASS: TestAddTask/ListTasks (0.00s)
    +PASS
    +cleaning up...
    +ok      github.com/rnemeth90/todo/cmd/todo      0.106s
     
    -
    - - - +
    - - -
    - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + -
    - - -
    -
    -
    -
    - - - + - + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2023-08-15-powershell-try-catch/index.html b/public/posts/2023-08-15-powershell-try-catch/index.html index 4a65b736..a7574f22 100644 --- a/public/posts/2023-08-15-powershell-try-catch/index.html +++ b/public/posts/2023-08-15-powershell-try-catch/index.html @@ -1,112 +1,82 @@ + - - - - - - - + + + Using try/catch/finally Blocks in PowerShell · GeekyRyan + + - - -Using try/catch/finally Blocks in PowerShell - GeekyRyan - - - - - - - - - + - - - + + + - + + + + + + + + + + + + + + + - - - - - - - - - + + + + - - + + + - - - - - + - + + + - - - - - - - + + + - - - + + - - - - - - - - - - - + + @@ -116,118 +86,124 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    +
    + - - - - - - - - - -
    - - - -
    -
    -
    -

    Using try/catch/finally Blocks in PowerShell

    - - -
    -
    -
    -

    Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it’s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we’ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn’t crash when the unexpected occurs. We’ll then cover the differences in terminating and non-terminating errors and why you should take these into consideration when implementing error handling.

    -

    The Try Block - - - - - -

    The Try block is where you place the code that might generate an error. Think of it as a protective bubble around your potentially troublesome code. If an error occurs within the Try block, PowerShell will immediately jump to the corresponding Catch block.

    +

    Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it’s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we’ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn’t crash when the unexpected occurs. We’ll then cover the differences in terminating and non-terminating errors and why you should take these into consideration when implementing error handling.

    +

    + The Try Block + + + Link to heading + +

    +

    The Try block is where you place the code that might generate an error. Think of it as a protective bubble around your potentially troublesome code. If an error occurs within the Try block, PowerShell will immediately jump to the corresponding Catch block.

    Here’s a simple example:

    try {
         # Code that might generate an error
    @@ -237,21 +213,23 @@ 

    The Try Block # Code to handle the error Write-Host "An error occurred: $_" } -

    The Catch Block - - - - - -

    The Catch block is where you can handle the error. PowerShell provides you with a special variable $_ that contains information about the error. You can use this variable to display error messages or even take corrective actions.

    +

    + The Catch Block + + + Link to heading + +

    +

    The Catch block is where you can handle the error. PowerShell provides you with a special variable $_ that contains information about the error. You can use this variable to display error messages or even take corrective actions.

    In the example above, we’re capturing the error generated by attempting to retrieve a nonexistent file. The $_ variable holds the error message, which we’re displaying using Write-Host.

    -

    The Finally Block - - - - - -

    Now, let’s talk about the unsung hero – the Finally block. This block is executed regardless of whether an error occurred or not. It’s where you can place cleanup code that ensures your script leaves no trace behind, even in the face of adversity. Some tasks that are commonly done in the finally block are closing database connections, removing temp files, etc. The finally block is completely optional.

    +

    + The Finally Block + + + Link to heading + +

    +

    Now, let’s talk about the unsung hero – the Finally block. This block is executed regardless of whether an error occurred or not. It’s where you can place cleanup code that ensures your script leaves no trace behind, even in the face of adversity. Some tasks that are commonly done in the finally block are closing database connections, removing temp files, etc. The finally block is completely optional.

    
     try {
         # Code that might generate an error
    @@ -265,13 +243,14 @@ 

    The Finally Block # Cleanup code here # ... } -

    Terminating/non-terminating Errors - - - - - -

    non-terminating errors are any error that will not stop the execution of your script. Most cmdlets in PowerShell are non-terminating. They may output an error, but your script will continue to run. These kinds of errors cannot be caught with a catch block by default. The reason for this is the default ErrorAction in your PowerShell profile, which is set to Continue.

    +

    + Terminating/non-terminating Errors + + + Link to heading + +

    +

    non-terminating errors are any error that will not stop the execution of your script. Most cmdlets in PowerShell are non-terminating. They may output an error, but your script will continue to run. These kinds of errors cannot be caught with a catch block by default. The reason for this is the default ErrorAction in your PowerShell profile, which is set to Continue.

    # To show your default error action type
     $ErrorActionPreference
     

    Let’s go back and look at our first example:

    @@ -294,13 +273,14 @@

    The Finally Block }

    Or you can change the ErrorActionPreference for the entire script, by adding this to the top of the script:

    $ErrorActionPreference = "Stop"
    -

    Exceptions - - - - - -

    If you have ever worked with exceptions in C# you can skip this section. In the previous examples, we used simple catch blocks that will catch any error. This is a good start, but we can do better. PowerShell allows you to catch individual exceptions based on the exception type, similar to how C# handles catching exceptions.

    +

    + Exceptions + + + Link to heading + +

    +

    If you have ever worked with exceptions in C# you can skip this section. In the previous examples, we used simple catch blocks that will catch any error. This is a good start, but we can do better. PowerShell allows you to catch individual exceptions based on the exception type, similar to how C# handles catching exceptions.

    Let’s look at an example:

    try {
         # Attempt to open a non-existent file
    @@ -313,258 +293,105 @@ 

    The Finally Block Write-Host "Caught an exception: $_" }

    We now have two catch blocks. If we encounter an exception of type System.IO.FileNotFoundException, the first catch block will catch the exception and handle it accordingly. The second catch block will handle any other generic error.

    -

    Conclusion - - - - - -

    Error handling might seem daunting at first, but with the power of Try-Catch-Finally blocks at your fingertips, you’re well-equipped to handle errors gracefully and ensure the resilience of your PowerShell scripts. Remember, every error is an opportunity to refine your skills and make your scripts more robust.

    +

    + Conclusion + + + Link to heading + +

    +

    Error handling might seem daunting at first, but with the power of Try-Catch-Finally blocks at your fingertips, you’re well-equipped to handle errors gracefully and ensure the resilience of your PowerShell scripts. Remember, every error is an opportunity to refine your skills and make your scripts more robust.

    Thanks for reading!

    Official Microsoft Documentation for Try-Catch-Finally in PowerShell: -about_try_catch_finally

    - - - - - +about_try_catch_finally

    + - - - - - - - - - - - - + + + + + + +
    +
    + © - + 2012 - - - - - - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. + +
    +
    + + + + + + + -
    - - -
    -
    -
    -
    - - - - - - + - - -
    - - - + -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/posts/2023-11-27-netcat/index.html b/public/posts/2023-11-27-netcat/index.html new file mode 100644 index 00000000..6319a661 --- /dev/null +++ b/public/posts/2023-11-27-netcat/index.html @@ -0,0 +1,413 @@ + + + + + + Exploring Netcat · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    +
    +
    +
    +

    + + Exploring Netcat + +

    +
    + +
    + +
    + +

    + Introduction + + + Link to heading + +

    +

    Netcat is a versatile networking utility that can be used for a wide range of tasks. It has often been referred to as the “network swiss-army knife”. Netcat was first released in the mid-90s, and I personally find it ironic to be blogging about it in 2023! But I feel like it is a somewhat cryptic tool, and new engineers or college graduates may not be familiar. This article is meant for those people who are not familiar with it, or have only briefly been exposed.

    +

    Netcat is a simple utility that reads and writes data across raw TCP/UDP sockets. Netcat is a command-line tool available out of the box on most *nix operating systems and can also be installed on Windows. It’s a powerful tool for debugging and investigating networks. It can even be used for tasks like port scanning, transferring files, chatting with friends on a network, and even creating backdoors (for testing purposes, obviously :) ).

    +

    + Understanding UDP + + + Link to heading + +

    +

    Before we dive into exploring UDP connections with netcat, let’s quickly get a refresher on UDP. UDP is a connectionless transport layer protocol that does not provide the same reliability, flow-control, and error-checking mechanisms as TCP. Unlike TCP, UDP also does not establish a persistent connection between the sender and receiver. Instead, it sends data packets, known as datagrams, individually using a ‘fire and forget’ method. UDP is often used for applications where real-time communication and low overhead are crucial, such as streaming media, gaming, DNS (though, certain functions of DNS may also use TCP), and IoT devices.

    +

    + Understanding TCP + + + Link to heading + +

    +

    It’s also crucial to have a fundamental knowledge of the TCP protocol. TCP is one of the main protocols in the Internet protocol suite, laying the foundation for the majority of data exchange over the Internet. Unlike its counterpart, UDP (User Datagram Protocol), TCP is connection-oriented, meaning a connection is established and maintained until the application programs at each end have finished exchanging messages. This ensures reliable, ordered, and error-checked delivery of a stream of data between applications running on hosts communicating over an IP network. Key features of TCP include its ability to manage data packet size, data transfer rate, and network traffic congestion, making it ideal for applications where data integrity and accuracy are crucial, such as web browsing, email, and file transfer. Understanding TCP is essential for effectively utilizing tools like Netcat, as it provides the basis for establishing stable and secure connections across a network.

    +

    + Creating a Simple Client/Server + + + Link to heading + +

    +

    The following will create a simple UDP server and client.

    +
      +
    1. Launch a shell and type the following command. This will tell netcat to listen (-l) on UDP (-u) port (-p) 5555.
    2. +
    +
    nc -l -u -p 5555
    +
      +
    1. Launch another shell and type the following. This will connect to the server we created above.
    2. +
    +
    nc -u 127.0.0.1 5555
    +
      +
    1. You can now send messages to the server, like so:
    2. +
    +

    Client:

    +
    $ nc -u 127.0.0.1 5555
    +hello
    +

    Server:

    +
    $ nc -l -u -p 5555
    +hello
    +

    You can do the same thing with TCP, just leave out the -u in each command above.

    +

    + Transfer a File + + + Link to heading + +

    +

    On the receiving end:

    +
    nc -l -p 5555 > outputfile
    +

    On the sending end:

    +
    nc [hostname or IP address of server] 5555 < inputfile
    +

    + Port Scanning: + + + Link to heading + +

    +
    netcat -v -z -n -w 1 v.txvip1 1-1023
    +

    + Serve a web page: + + + Link to heading + +

    +

    If you have an html file, you can create a simple web server for it. Here we tell netcat to listen on port 8080 and redirect the contents of index.html to any ’thing’ that connects:

    +
    nc -l -p 8080 < index.html
    +

    Note: In the examples above, I always use port 5555. You can technically use just about any port you want. However, attempting to use any port below 1024 will require root privileges. The port you choose cannot be in use by another process.

    +

    + Other Practical Examples + + + Link to heading + +

    +

    Let’s explore a few more practical examples to illustrate the usefulness of netcat’s UDP capabilities. I will leave the actual implementation as an exercise for you to try.

    +

    + Example 1: Testing a TCP/UDP Server + + + Link to heading + +

    +

    Suppose you are developing a UDP server application, and you want to test its functionality. You can use netcat to send TCP/UDP packets to your server and observe its response. By monitoring the server’s behavior, you can ensure that it correctly handles incoming UDP traffic.

    +

    + Example 2: Interacting with Networked Devices + + + Link to heading + +

    +

    Netcat can be handy when interacting with networked devices, such as routers, IoT devices, or even network-enabled printers. By establishing a TCP/UDP connection, you can send commands, queries, or configuration data to these devices, enabling you to troubleshoot or configure them remotely.

    +

    + Example 3. Banner Grabbing + + + Link to heading + +

    +

    This is a technique used in network security to gather information about a remote server, including the type and version of the operating system and applications running. The basic concept is that you connect to a network service and see what kind of ‘banner’ (if any) it returns in the output. When I was starting out in the IT world, this was a common thing to do to enumerate devices and services on a network. Though, I would like to believe this is no longer as much of a concern, given the simplicity of preventing this type of information discovery attack.

    +

    + Conclusion + + + Link to heading + +

    +

    Netcat’s ability to handle UDP connections makes it an invaluable tool for various network-related tasks. Whether you are testing a UDP server, interacting with networked devices, or exploring your network’s services, netcat provides a convenient and straightforward approach.

    +

    In this blog post, we walked through the process of creating a UDP connection using netcat, discussed the fundamentals of UDP, and explored practical examples where netcat can prove useful. By mastering netcat’s capabilities, you can enhance your network troubleshooting and debugging skills, and gain a deeper understanding of UDP communication.

    +

    You can read more about netcat in the man pages:

    +
    man nc
    +

    The OpenBSD repository contains the original source written by Hobbit decades ago: +netcat.c

    + +
    + + +
    + + + + + + + + + + +
    +
    + + +
    + +
    + +
    +
    + © + + 2012 - + + 2024 + Ryan Nemeth + · + + Powered by Hugo & Coder. + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/posts/2023-12-04-nginx-ingress-resp-header-size/index.html b/public/posts/2023-12-04-nginx-ingress-resp-header-size/index.html new file mode 100644 index 00000000..a4576cf2 --- /dev/null +++ b/public/posts/2023-12-04-nginx-ingress-resp-header-size/index.html @@ -0,0 +1,325 @@ + + + + + + Nginx Ingress Response Header Size - A Cautionary Tale · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    +
    +
    +
    +

    + + Nginx Ingress Response Header Size - A Cautionary Tale + +

    +
    + +
    + +
    + +

    This will be a short post about a recent issue I encountered when using Nginx as a Kubernetes ingress. Though, this could also be encountered when using Nginx as a reverse proxy as well. The two definitions are functionally similar.

    +

    We recently had a client call in complaining of our application returning random 502s (Bad Gateway).

    +

    After some investigation and the common finger-pointing, I found this entry in the logs of our ingress controllers:

    +

    note this log entry is truncated

    +
    [error] 193#193: 
    +    *25 upstream sent too big header while reading response header from upstream
    +

    This error message pointed towards a limitation in Nginx’s default configuration - it struggles with large headers. This is a known quirk of Nginx, contrasting with some other web servers that can handle larger headers by default.

    +

    We later found that this client’s large HTTP headers were due to a large content security policy header.

    +

    The solution seemed straightforward: increase the buffer size in Nginx to accommodate larger headers. For a typical Nginx setup, this could be achieved by tweaking the configuration file:

    +
    proxy_buffers 8 16k;  # 8 buffers of 16k each
    +proxy_buffer_size 16k; # 16k for headers
    +

    However, the situation gets a bit more complex when dealing with Nginx as an ingress controller in a Kubernetes environment.

    +

    + Configuring Nginx Ingress controller + + + Link to heading + +

    +

    Fortunately, the Nginx Ingress controller is designed to cater to such customizations. It allows configuration changes through a Kubernetes ConfigMap, which maps to Nginx’s internal settings. To adjust the buffer size, you need to:

    +
      +
    1. Deploy a ConfigMap with your desired settings, or add entries to an existing ConfigMap. For example, setting proxy-buffer-size to “16k” to handle larger headers:
    2. +
    +
    kind: ConfigMap
    +apiVersion: v1
    +metadata:
    +  name: nginx-configuration
    +  namespace: kube-system
    +data:
    +  proxy-buffer-size: "16k"
    +

    If creating a new ConfigMap, you will need to tell Nginx pods to read it. This involves passing the name of your ConfigMap as an argument in your deployment configuration:

    +
    args:
    +  - /nginx-ingress-controller
    +  - --configmap=$(POD_NAMESPACE)/nginx-configuration
    +

    Once the ConfigMap is in place, the Nginx pods will pickup and apply the new settings

    + +
    + + +
    + + + + + + + + + + +
    +
    + + +
    + +
    + +
    +
    + © + + 2012 - + + 2024 + Ryan Nemeth + · + + Powered by Hugo & Coder. + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/posts/2023-12-12-golang-url-validation/index.html b/public/posts/2023-12-12-golang-url-validation/index.html new file mode 100644 index 00000000..6718e392 --- /dev/null +++ b/public/posts/2023-12-12-golang-url-validation/index.html @@ -0,0 +1,337 @@ + + + + + + Validating URLs with Go · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    +
    +
    +
    +

    + + Validating URLs with Go + +

    +
    + +
    + +
    + +

    + Introduction + + + Link to heading + +

    +

    In this post, we’ll take a quick look at URL validation using Golang. It’s common to implement URL validation as a task within a HTTP request pipeline, typically as middleware. There are many different definitions of “validation”. For the purpose of this article, we will simply validate that a URL conforms to a particular text pattern.

    +

    I often see people (mistakenly) use URL and URI interchangeably. URL is actually is a sub-type of URI. A URL is a reference to a web resource, typically seen as a web address (e.g. https://golang.org/project/). A URI, on the other hand, can be used to identify any type of resource, not just those on the internet.

    +

    To validate a URL in Go, we could test our URL against a regex pattern, such as https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*). However, the Golang team was nice enough to provide this functionality to us via the net/url package.

    +

    To validate a URL, we can simply use the url.ParseRequestURI() function. The definition of this function is below (taken from pkg.go.dev)

    +
    func ParseRequestURI(rawurl string) (*URL, error)
    +
    +ParseRequestURI parses rawurl into a URL structure. It assumes that rawurl was received in an HTTP request, so the rawurl is interpreted only as an absolute URI or an absolute path. The string rawurl is assumed not to have a #fragment suffix. (Web browsers strip #fragment before sending the URL to a web server.)
    +

    Let’s see how we can use url.ParseRequestURI():

    +
    package main
    +
    +import (
    +  "log"
    +  "net/url"
    +)
    +
    +func main() {
    +  u, err := url.ParseRequestURI("hello")
    +  log.Printf("err=%+v url=%+v\n", err, u)
    +
    +  u, err = url.ParseRequestURI("http://rnemeth90.github.com/")
    +  log.Printf("err=%+v url=%+v\n", err, u)
    +
    +  u, err = url.ParseRequestURI("http://golang.org/index.html?#page1")
    +  log.Printf("err=%+v url=%+v\n", err, u)
    +
    +  u, err = url.ParseRequestURI("golang.org")
    +  log.Printf("err=%+v url=%+v\n", err, u)
    +}
    +

    Which outputs the following:

    +
    2023/12/19 19:50:07 err=parse "hello": invalid URI for request url=<nil>
    +2023/12/19 19:50:07 err=<nil> url=http://rnemeth90.github.com/
    +2023/12/19 19:50:07 err=<nil> url=http://golang.org/index.html?#page1
    +2023/12/19 19:50:07 err=parse "golang.org": invalid URI for request url=<nil>
    +

    That’s it! This is a short article, but it’s just that easy to validate URLs in Go. I was learning about this recently and wanted to document what I learned. Until next time!

    + +
    + + +
    + + + + + + + + + + +
    +
    + + +
    + +
    + +
    +
    + © + + 2012 - + + 2024 + Ryan Nemeth + · + + Powered by Hugo & Coder. + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/posts/2024-03-27-golang-detect-file-type/index.html b/public/posts/2024-03-27-golang-detect-file-type/index.html new file mode 100644 index 00000000..5d930d72 --- /dev/null +++ b/public/posts/2024-03-27-golang-detect-file-type/index.html @@ -0,0 +1,342 @@ + + + + + + Detecting MIME Types in Go · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    +
    +
    +
    +

    + + Detecting MIME Types in Go + +

    +
    + +
    + +
    + +

    + Introduction + + + Link to heading + +

    +

    Knowing the type of a file you’re working with is not just a matter of curiosity — it’s often a necessity. This is especially true when you’re deciding whether or not a particular operation can be carried out on that file. Go, with its comprehensive standard library, offers a straightforward approach to identifying a file’s MIME type, ensuring that developers have the tools they need to make informed decisions about file manipulation. You may expect to find this functionality in the file package, but you’d be wrong! Read on…

    +

    + The net/http Package: Your Gateway to MIME Detection + + + Link to heading + +

    +

    At the heart of Go’s approach to MIME type detection is the net/http package. This package provides everything developers need for identifying file types. The method in question, DetectContentType(), is nothing short of a detective dedicated to uncovering the secrets held within the first 512 bytes of a file.

    +

    Imagine you’re downloading an image for processing from a URL, but before you proceed, you need to confirm its type. Here’s how you’d go about it:

    +
    resp, err := client.Get("https://rnemeth90.github.io/images/synology-cloud-sync-01.png")
    +if err != nil {
    +	log.Fatal(err)
    +}
    +defer resp.Body.Close()
    +
    +bytes, err := ioutil.ReadAll(resp.Body)
    +if err != nil {
    +	log.Fatal(err)
    +}
    +
    +// detecting the MIME type
    +mimeType := http.DetectContentType(bytes)
    +fmt.Println(mimeType) // Voila! It's an image/png
    +

    In this snippet, DetectContentType() takes the stage, examining the initial bytes of the file and returning a MIME type, such as image/png. Should it find itself at a loss, unable to pin down the file’s type, it defaults to application/octet-stream, a way of saying, “This is a file, but beyond that, you’re on your own.”

    +

    + Beyond the Basics: When You Need More + + + Link to heading + +

    +

    While DetectContentType() serves well for a number of common file types, its repertoire is not unlimited. There are scenarios where you might find yourself needing to identify more obscure or specific file types. This is where the mimetype library steps in, offering a more extensive catalog of file types. If DetectContentType() isn’t able to help you, considering this library might just be your next move.

    +

    + Conclusion + + + Link to heading + +

    +

    Go’s net/http package, with its DetectContentType() method, provides a solid foundation for this task. And for those times when you need to go further, the mimetype library is there to help.

    +

    Whether you’re safeguarding against the wrong file types in an upload process or curating content based on its nature, understanding and utilizing MIME type detection is an invaluable skill. Thanks for reading!

    + +
    + + +
    + + + + + + + + + + +
    +
    + + +
    + +
    + +
    +
    + © + + 2012 - + + 2024 + Ryan Nemeth + · + + Powered by Hugo & Coder. + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/posts/2024-06-29-mount-multiple-kubernetes-secrets-into-one-directory/index.html b/public/posts/2024-06-29-mount-multiple-kubernetes-secrets-into-one-directory/index.html new file mode 100644 index 00000000..3c5704ea --- /dev/null +++ b/public/posts/2024-06-29-mount-multiple-kubernetes-secrets-into-one-directory/index.html @@ -0,0 +1,359 @@ + + + + + + Mounting Multiple Kubernetes Secrets into One Directory · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    +
    +
    +
    +

    + + Mounting Multiple Kubernetes Secrets into One Directory + +

    +
    + +
    + +
    + +

    + Introduction + + + Link to heading + +

    +

    Combining multiple Kubernetes secrets into a single directory can streamline secret management in your applications. This guide walks you through the process of achieving this in Kubernetes, ensuring efficient and organized secret management.

    +

    + Creating Secrets + + + Link to heading + +

    +

    First, create your secrets using the kubectl create secret command:

    +
    kubectl create secret generic secret-one --from-literal=key1=value1
    +kubectl create secret generic secret-two --from-literal=key2=value2
    +

    Each secret can contain multiple key-value pairs, and you can add more secrets as needed.

    +

    + Configuring the Pod + + + Link to heading + +

    +

    Next, define the pod configuration to mount these secrets into a single directory. Here’s an example configuration:

    +
    apiVersion: v1
    +kind: Pod
    +metadata:
    +  name: mypod
    +spec:
    +  containers:
    +  - name: mycontainer
    +    image: myimage
    +    volumeMounts:
    +    - name: secret-volume1
    +      mountPath: "/etc/secrets/secret-one"
    +      subPath: key1
    +    - name: secret-volume2
    +      mountPath: "/etc/secrets/secret-two"
    +      subPath: key2
    +  volumes:
    +  - name: secret-volume1
    +    secret:
    +      secretName: secret-one
    +  - name: secret-volume2
    +    secret:
    +      secretName: secret-two
    +

    + Detailed Explanation + + + Link to heading + +

    +
      +
    • Volume Mounts: The volumeMounts section specifies where the secrets will be mounted within the container’s file system. By using the subPath property, you can place each secret’s content into a specific file within the target directory.
    • +
    • Volumes: The volumes section links each volume to a Kubernetes secret. This ensures that the secrets are available to the container at runtime.
    • +
    +

    In this example, secret-one and secret-two are mounted into /etc/secrets/secret-one and /etc/secrets/secret-two, respectively. The subPath ensures that each key-value pair from the secrets is mapped to a separate file within the specified directory.

    +

    + Conclusion + + + Link to heading + +

    +

    By mounting secrets into subdirectories using the subPath property, you can effectively manage multiple secrets within a single directory. This method enhances organization and accessibility, making it easier to handle secrets in your Kubernetes applications.

    + +
    + + +
    + + + + + + + + + + +
    +
    + + +
    + +
    + +
    +
    + © + + 2012 - + + 2024 + Ryan Nemeth + · + + Powered by Hugo & Coder. + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/posts/index.html b/public/posts/index.html index 9e1d5fa0..d7fbf69c 100644 --- a/public/posts/index.html +++ b/public/posts/index.html @@ -1,3853 +1,376 @@ + - - - - - - - + + + Posts · GeekyRyan + + - - -Posts - GeekyRyan + - + + + - - - + + + - + + + + + + - - - + + + + - - - - - + + + - - - + - + + - - - - - - - - - - - - + + + + + + - - - - + + - - - + - - - - - - - - - + - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    -
    -
    - -
    - -
    - -
    -

    Posts

    + + + -
    -
    -
    -

    Using try/catch/finally Blocks in PowerShell

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Golang: When Identical Strings are Not Equal

    - -
    -
    - - + +
  • 2
  • + - - - - -
    + -
    -
    -
    -

    Handling Graceful Shutdown in a .NET App Hosted in Kubernetes

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Backup Synology NAS to Azure Storage

    - -
    -
    - - + +
  • 3
  • + - - - - -
    + -
    -
    -
    -

    Building a Golang App with Github Actions

    - -
    -
    - - + - - - - -
    + -
    -
    -
    -

    Chaining YAML Pipelines in Azure Devops

    - -
    -
    - - + - - - - -
    + + + + -
    -
    -
    -

    Update Azure Devops SPN Secret

    - -
    -
    - - + - - - - -
    + + -
    -
    -
    -

    Use “replace” in go.mod to Point to a Local Module

    - -
    -
    - - + - - - - -
    + + -
    -
    -
    -

    Powershell for Devops - Querying REST APIs with Powershell

    - -
    -
    - - + - - - - -
    - -
    -
    -
    -

    Reading Json Files with Go

    - -
    -
    - +
    +
    + © - - -
    +
    - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ - Ryan - +
    -
    - - - - - - -
    -
    + - - -
    -
    -
    -

    AKS Scale Down Mode

    - -
    -
    - + + + + - + + - -
    - -
    -
    -
    -

    Scheduled Kubernetes Worker Node Maintenance with Kured

    - -
    -
    - + - + + - + -
    - -
    -
    -
    -

    Running Docker in WSL v1

    - -
    -
    - + - + + - + -
    - -
    -
    -
    -

    EF Core &#8211; Unable to create an object of type DbContext

    - -
    -
    - + - + + - - - -
    - -
    -
    -
    -

    Remove Kubernetes Namespace Stuck in the Terminating State

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Injecting multiple Kubernetes volumes to the same directory in a pod

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Kubernetes Storage Simplified

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Accessing Secrets Securely in Azure DevOps Pipelines

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Kubernetes Pod Eviction

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Azure Kubernetes sFTP Solution

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    WSUS: Update Files Not Downloading

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Active Directory Migration Toolkit The RPC Server is Unavailable

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Continuous Deployment Models

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Deploy Azure VMs Using Azure Devops CI/CD Pipeline

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Azure Devops &#8211; Self Hosted Agent Service Won&#8217;t Start &#8211; Incorrect Function

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Azure Tenant Maintenance &#8211; Purge Empty Resource Groups

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Exam AZ-303: Microsoft Azure Architect Technologies Study Guide

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Azure AD Sync &#8211; Set-MsolDirSyncEnabled : You cannot turn off Active Directory synchronization.

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Azure VM Scale Set &#8211; Get Instance IP Address

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Azure Policy &#8211; Allowed Locations for Resource Deployment

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Replicate an Azure VM Image Between Regions

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Reset GRUB/root Password for vCenter/PSC Appliance

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Deploy a New ADDS Forest on Server 2019 Core

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Could not connect to VMware Directory Service via LDAP when Deploying New vCenter Appliance

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Cisco AnyConnect &#8211; VPN Establishment Capability from a Remote Desktop is Disabled

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Error When Reinstalling DirSync

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Active Directory Migration Toolkit &#8211; The RPC Server is Unavailable (hr=0x800706ba)

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Azure Site Recovery &#8211; VMware-to-Azure: Wrong IP address discovered for VM

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Azure AD Connect No-Start-Connection

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Azure AD Connect Health: Latest Data is not Available in Azure Portal

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Removing a Forest from Azure AD Connect

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Remove Stubborn PSC or vCenter Appliance from an SSO Domain

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Exchange 2016 Hybrid Deploy Check: Username or Password Invalid

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Migrate Windows Deployment Services to New Server

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    New Script: BulkAdd-SpamFilterWhitelist.ps1

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Windows 8 File History

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    How to Permanently Remove Office 365 Users

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Access is Denied When Attempting to Delete a Dynamic Distribution Group

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Running vSphere in VMware Workstation 12

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    WSUS: Update Files Not Downloading (Content File Download Failed)

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    WSUS: An error occurred trying to connect the WSUS server

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    WDS Service: The Service did not respond in a timely fashion

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Script to Move All Disabled AD Objects to a Specified OU

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Exchange 2013: Error 0x80070070 While Adding DAG Member

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Script for Setting the License for Multiple Office 365 User Accounts

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    The User Profile Service service failed the logon

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Azure AD Connect Password Sync &#8211; Disabled and Grayed Out

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Finding All Mailboxes with a Forwarding Address in Exchange 2003

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Script for Querying All AD Computers Time Source

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Error When Reinstalling DirSync

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Failed to Mount Exchange 2010 Database

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Ping Sweeping with FPing

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Powershell: SID to Username

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    DHCP Address Negotiation Process

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Unlock a Domain User from CMD Line

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    The Case of Transitive Trusts and Dropped RPC Connections

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Creating Applocker Policies

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    TCP/IP Network Fundamentals

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    BranchCache

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    File History

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    Layer 2 Switching Fundamentals

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    User Account Control

    - -
    -
    - - - - - - - -
    - -
    -
    -
    -

    User Account Control

    - -
    -
    - - - - - - - -
    - - - - - - -
    - - - - - -

    - - Ryan Nemeth - - - / - - - - - - -

    -
    - - - - diff --git a/public/posts/index.xml b/public/posts/index.xml index 6f976453..45411543 100644 --- a/public/posts/index.xml +++ b/public/posts/index.xml @@ -2,3529 +2,557 @@ Posts on GeekyRyan - https://rnemeth90.github.io/posts/ - GeekyRyan (Posts) - Hugo -- gohugo.io - en-us - Tue, 15 Aug 2023 00:00:00 +0000 - - - - + http://localhost:1313/posts/ + Recent content in Posts on GeekyRyan + Hugo + en + Sat, 29 Jun 2024 00:00:00 +0000 + + + Mounting Multiple Kubernetes Secrets into One Directory + http://localhost:1313/posts/2024-06-29-mount-multiple-kubernetes-secrets-into-one-directory/ + Sat, 29 Jun 2024 00:00:00 +0000 + http://localhost:1313/posts/2024-06-29-mount-multiple-kubernetes-secrets-into-one-directory/ + Introduction Link to heading Combining multiple Kubernetes secrets into a single directory can streamline secret management in your applications. This guide walks you through the process of achieving this in Kubernetes, ensuring efficient and organized secret management. Creating Secrets Link to heading First, create your secrets using the kubectl create secret command: kubectl create secret generic secret-one --from-literal=key1=value1 kubectl create secret generic secret-two --from-literal=key2=value2 Each secret can contain multiple key-value pairs, and you can add more secrets as needed. + + + Detecting MIME Types in Go + http://localhost:1313/posts/2024-03-27-golang-detect-file-type/ + Wed, 27 Mar 2024 00:00:00 +0000 + http://localhost:1313/posts/2024-03-27-golang-detect-file-type/ + Introduction Link to heading Knowing the type of a file you&rsquo;re working with is not just a matter of curiosity — it&rsquo;s often a necessity. This is especially true when you&rsquo;re deciding whether or not a particular operation can be carried out on that file. Go, with its comprehensive standard library, offers a straightforward approach to identifying a file&rsquo;s MIME type, ensuring that developers have the tools they need to make informed decisions about file manipulation. + + + Validating URLs with Go + http://localhost:1313/posts/2023-12-12-golang-url-validation/ + Tue, 19 Dec 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-12-12-golang-url-validation/ + Introduction Link to heading In this post, we&rsquo;ll take a quick look at URL validation using Golang. It&rsquo;s common to implement URL validation as a task within a HTTP request pipeline, typically as middleware. There are many different definitions of &ldquo;validation&rdquo;. For the purpose of this article, we will simply validate that a URL conforms to a particular text pattern. I often see people (mistakenly) use URL and URI interchangeably. + + + Nginx Ingress Response Header Size - A Cautionary Tale + http://localhost:1313/posts/2023-12-04-nginx-ingress-resp-header-size/ + Mon, 11 Dec 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-12-04-nginx-ingress-resp-header-size/ + This will be a short post about a recent issue I encountered when using Nginx as a Kubernetes ingress. Though, this could also be encountered when using Nginx as a reverse proxy as well. The two definitions are functionally similar. We recently had a client call in complaining of our application returning random 502s (Bad Gateway). After some investigation and the common finger-pointing, I found this entry in the logs of our ingress controllers: + + + Exploring Netcat + http://localhost:1313/posts/2023-11-27-netcat/ + Mon, 27 Nov 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-11-27-netcat/ + Introduction Link to heading Netcat is a versatile networking utility that can be used for a wide range of tasks. It has often been referred to as the &ldquo;network swiss-army knife&rdquo;. Netcat was first released in the mid-90s, and I personally find it ironic to be blogging about it in 2023! But I feel like it is a somewhat cryptic tool, and new engineers or college graduates may not be familiar. + Using try/catch/finally Blocks in PowerShell - https://rnemeth90.github.io/posts/2023-08-15-powershell-try-catch/ + http://localhost:1313/posts/2023-08-15-powershell-try-catch/ Tue, 15 Aug 2023 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2023-08-15-powershell-try-catch/ - <p>Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it&rsquo;s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we&rsquo;ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn&rsquo;t crash when the unexpected occurs. We&rsquo;ll then cover the differences in terminating and non-terminating errors and why you should take these into consideration when implementing error handling.</p> -<h2 id="the-try-block" >The Try Block -<span> - <a href="#the-try-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The Try block is where you place the code that might generate an error. Think of it as a protective bubble around your potentially troublesome code. If an error occurs within the Try block, PowerShell will immediately jump to the corresponding Catch block.</p> -<p>Here&rsquo;s a simple example:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><h2 id="the-catch-block" >The Catch Block -<span> - <a href="#the-catch-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The Catch block is where you can handle the error. PowerShell provides you with a special variable $_ that contains information about the error. You can use this variable to display error messages or even take corrective actions.</p> -<p>In the example above, we&rsquo;re capturing the error generated by attempting to retrieve a nonexistent file. The $_ variable holds the error message, which we&rsquo;re displaying using Write-Host.</p> -<h2 id="the-finally-block" >The Finally Block -<span> - <a href="#the-finally-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Now, let&rsquo;s talk about the unsung hero – the Finally block. This block is executed regardless of whether an error occurred or not. It&rsquo;s where you can place cleanup code that ensures your script leaves no trace behind, even in the face of adversity. Some tasks that are commonly done in the finally block are closing database connections, removing temp files, etc. The finally block is completely optional.</p> -<pre tabindex="0"><code> -try { - # Code that might generate an error - # ... -} -catch { - # Code to handle the error - # ... -} -finally { - # Cleanup code here - # ... -} -</code></pre><h2 id="terminatingnon-terminating-errors" >Terminating/non-terminating Errors -<span> - <a href="#terminatingnon-terminating-errors"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>non-terminating errors are any error that will not stop the execution of your script. Most cmdlets in PowerShell are non-terminating. They may output an error, but your script will continue to run. These kinds of errors cannot be caught with a catch block by default. The reason for this is the default <code>ErrorAction</code> in your PowerShell profile, which is set to <code>Continue</code>.</p> -<pre tabindex="0"><code># To show your default error action type -$ErrorActionPreference -</code></pre><p>Let&rsquo;s go back and look at our first example:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><p>If you took the time to run this code, you may have noticed that the <code>Write-Host</code> cmdlet in the <code>catch</code> block was never ran. Why did we get a red error message in our PowerShell console, rather than the text <code>An error occurred: ...</code>? The reason is that the non-existing path isn&rsquo;t a terminating error, and the default <code>ErrorAction</code> is <code>Continue</code>. To catch the error, you will need to change the <code>ErrorAction</code> in your PowerShell console to <code>Stop</code>. This can be done in multiple ways. You can add <code>-ErrorAction Stop</code> to the cmdlet, like this:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -ErrorAction Stop -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><p>Or you can change the <code>ErrorActionPreference</code> for the entire script, by adding this to the top of the script:</p> -<pre tabindex="0"><code>$ErrorActionPreference = &#34;Stop&#34; -</code></pre><h2 id="exceptions" >Exceptions -<span> - <a href="#exceptions"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>If you have ever worked with exceptions in C# you can skip this section. In the previous examples, we used simple <code>catch</code> blocks that will catch <em>any</em> error. This is a good start, but we can do better. PowerShell allows you to catch individual exceptions based on the exception type, similar to how C# handles catching exceptions.</p> -<p>Let&rsquo;s look at an example:</p> -<pre tabindex="0"><code>try { - # Attempt to open a non-existent file - $file = Get-Content -Path &#34;NonexistentFile.txt&#34; -} -catch [System.IO.FileNotFoundException] { - Write-Host &#34;Caught a FileNotFoundException: $_&#34; -} -catch { - Write-Host &#34;Caught an exception: $_&#34; -} -</code></pre><p>We now have two <code>catch</code> blocks. If we encounter an exception of type <code>System.IO.FileNotFoundException</code>, the first <code>catch</code> block will catch the exception and handle it accordingly. The second <code>catch</code> block will handle any other generic error.</p> -<h2 id="conclusion" >Conclusion -<span> - <a href="#conclusion"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Error handling might seem daunting at first, but with the power of Try-Catch-Finally blocks at your fingertips, you&rsquo;re well-equipped to handle errors gracefully and ensure the resilience of your PowerShell scripts. Remember, every error is an opportunity to refine your skills and make your scripts more robust.</p> -<p>Thanks for reading!</p> -<p>Official Microsoft Documentation for Try-Catch-Finally in PowerShell: -<a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-7.3">about_try_catch_finally</a></p> - - - + http://localhost:1313/posts/2023-08-15-powershell-try-catch/ + Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it&rsquo;s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we&rsquo;ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn&rsquo;t crash when the unexpected occurs. + Golang: When Identical Strings are Not Equal - https://rnemeth90.github.io/posts/2023-01-24-golang-strings-not-equal/ + http://localhost:1313/posts/2023-01-24-golang-strings-not-equal/ Tue, 24 Jan 2023 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2023-01-24-golang-strings-not-equal/ - <p><em>This will be a quick and dirty post, so please forgive any spelling/grammar mistakes.</em></p> -<p>I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don&rsquo;t write a ton of code at work (mostly just scripting/pipelines when I do), so I&rsquo;m constantly working on something like this in my spare time. Anyway, I was writing this app, got everything working like I wanted it to. I then wrote some of the tests and was iterating over them. I noticed the <code>ListTasks</code> test was failing:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TestAddTask</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">task</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;test task number 1&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Getwd</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmdPath</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">binaryName</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;AddNewTask&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-add&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">Run</span>(); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// failing test -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;ListTasks&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-list&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">out</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">CombinedOutput</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">expected</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;[ ] 1: %s&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Compare</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#a6e22e">expected</span>) <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;got %v, expected %v\n&#34;</span>, <span style="color:#a6e22e">out</span>, []byte(<span style="color:#a6e22e">expected</span>)) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Seems strange, considering the strings appear to be equivalent in the output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span> main_test.go:82: got <span style="color:#f92672">[</span> <span style="color:#f92672">]</span> 1: test task number <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> , expected <span style="color:#f92672">[</span> <span style="color:#f92672">]</span> 1: test task number <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>--- FAIL: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- FAIL: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>FAIL -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>exit status <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>FAIL github.com/rnemeth90/todo/cmd/todo 0.105s -</span></span></code></pre></div><p>What could be happening? After banging my head on the desk a few times, a revelation came to me&hellip;</p> -<p>In Go, strings are simply slices of bytes. I decided to print out each string as a byte array:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span> main_test.go:80: got <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">10</span> 10<span style="color:#f92672">]</span>, expected <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> 49<span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span>--- FAIL: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- FAIL: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>FAIL -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>exit status <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>FAIL github.com/rnemeth90/todo/cmd/todo 0.144s -</span></span></code></pre></div><p>Let&rsquo;s take a closer look at the byte arrays from the test output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>got <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">10</span> 10<span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span>expected <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> 49<span style="color:#f92672">]</span> -</span></span></code></pre></div><p>We can see the byte array returned from <code>cmd.CombinedOutput()</code> has some additional bytes in it at the end (32,10,10). What exactly are 32, 10, and 10? To figure this out, I went over to the go playground: <a href="https://go.dev/play/">https://go.dev/play/</a>.</p> -<p>Let&rsquo;s see what happens when we create a byte array with a single number and print it out as a string to the console:</p> -<p><a href="https://rnemeth90.github.io/images/golang-strings-not-equal-01.png"><img src="https://rnemeth90.github.io/images/golang-strings-not-equal-01.png" alt=""></a></p> -<p>Interesting, we can see that <code>m</code> was output to the console. So what do our mysterious additional characters in our test result represent? Let&rsquo;s see:</p> -<p><a href="https://rnemeth90.github.io/images/golang-strings-not-equal-02.png"><img src="https://rnemeth90.github.io/images/golang-strings-not-equal-02.png" alt=""></a></p> -<p>It&rsquo;s hard to tell from the output, but if you look in the results pane, you&rsquo;ll see a space and two new lines. So <code>32</code> represents a space, and <code>10</code> represents a new line!</p> -<p>You can play with this code yourself: <a href="https://go.dev/play/p/fGUIxJM6KnV">https://go.dev/play/p/fGUIxJM6KnV</a></p> -<p>Ok, so let&rsquo;s fix our failing test:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TestAddTask</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">task</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;test task number 1&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Getwd</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmdPath</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">binaryName</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;AddNewTask&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-add&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">Run</span>(); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;ListTasks&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-list&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">out</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">CombinedOutput</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// add this line -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">out</span> = []byte(<span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">TrimSuffix</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#e6db74">&#34; \n\n&#34;</span>)) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">expected</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;[ ] 1: %s&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Compare</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#a6e22e">expected</span>) <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;got %v, expected %v\n&#34;</span>, <span style="color:#a6e22e">out</span>, []byte(<span style="color:#a6e22e">expected</span>)) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>The <code>strings</code> package has a <code>TrimSuffix</code> function that is useful for trimming bits off the end of a string. In the code above, you can see that we added <code>out = []byte(strings.TrimSuffix(string(out), &quot; \n\n&quot;))</code>, which will trim off the space (character 32) and the two new lines (character 10). Now when we run our integration test, it passes:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span>--- PASS: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>PASS -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>ok github.com/rnemeth90/todo/cmd/todo 0.106s -</span></span></code></pre></div> - - + http://localhost:1313/posts/2023-01-24-golang-strings-not-equal/ + This will be a quick and dirty post, so please forgive any spelling/grammar mistakes. I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don&rsquo;t write a ton of code at work (mostly just scripting/pipelines when I do), so I&rsquo;m constantly working on something like this in my spare time. + Handling Graceful Shutdown in a .NET App Hosted in Kubernetes - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ Wed, 28 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ - <p>I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. It was actually a combination of these blogs (and the resolutions posted) that ended up resolving our issue.</p> -<h3 id="so-what-was-actually-causing-the-502s" >So what was actually causing the 502&rsquo;s? -<span> - <a href="#so-what-was-actually-causing-the-502s"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h3><p>As stated, these APIs are hosted in Kubernetes. They are written primarily in c# (.NET Framework) and hosted in Windows Server Core containers. The pods are load balanced using a service, and we have an Nginx ingress on top of the service. Nothing fancy, just a typical setup that you may have seen or even built yourself. We implement automatic scaling for our replica sets using a standard Kubernetes-native HPA or Keda, depending on the app. We have autoscale rules defined for the pods. Our clusters are hosted in Azure Kubernetes Service, and we autoscale our node pools. So, there are several layers of scaling happening in our clusters at any given time. Occasionally, when a pod was handling a client request, Kubelet or a controller would come along and scale the pod in. We were initially under the belief that the <code>terminationGracePeriodSeconds</code> value within our deployment would allow the pod to continue running for the defined number of seconds. However, we were mistaken. This value tells Kubernetes to allow the application running within the pod some time to clean up. It does <em>not</em> tell the app to continue running for the defined number of seconds after it receives a sigterm signal. This logic actually needs to be implemented within the application itself, or with a prestop hook. The prestop method is <a href="https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/">well documented</a>, so I will not cover it here.</p> -<p>To implement this in a .NET Framework app running in Windows, you need to add this registry key to your container.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">RUN</span> reg add hklm<span style="color:#ae81ff">\s</span>ystem<span style="color:#ae81ff">\c</span>urrentcontrolset<span style="color:#ae81ff">\c</span>ontrol /v WaitToKillServiceTimeout /t REG_SZ /d <span style="color:#ae81ff">60000</span> /f<span style="color:#960050;background-color:#1e0010"> -</span></span></span></code></pre></div><p>This value tells Windows to wait a number of milliseconds before shutting down Normally, Windows only waits for 5 seconds (default) before shutting down any &lsquo;background&rsquo; processes. Windows forcibly shuts down processes after this period of time.</p> -<p>Next, in the startup class, we&rsquo;ll add the following code. I have added inline comments to explain.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c#" data-lang="c#"><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">namespace</span> MyApp.APIConsoleHost -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Program</span> -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Register the SetConsoleCtrlHandler function in kernel32.dll in the -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> application to capture CTRL_SHUTDOWN_EVENT events for resource reclamation -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e"> [DllImport(&#34;Kernel32&#34;)]</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">extern</span> <span style="color:#66d9ef">bool</span> SetConsoleCtrlHandler(HandlerRoutine handler, <span style="color:#66d9ef">bool</span> <span style="color:#66d9ef">add</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Define a delegate for our handler routine</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">delegate</span> <span style="color:#66d9ef">bool</span> HandlerRoutine(CtrlTypes ctrlType); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">volatile</span> ManualResetEvent _exitEvent = <span style="color:#66d9ef">new</span> ManualResetEvent(<span style="color:#66d9ef">false</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> HandlerRoutine _handler; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Define the event types that we want to handle when the application receives a SIGTERM -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_C_EVENT = 0, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_BREAK_EVENT = 1, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_CLOSE_EVENT = 2, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_LOGOFF_EVENT = 5, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_SHUTDOWN_EVENT = 6 -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">enum</span> CtrlTypes -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> CTRL_SHUTDOWN_EVENT = <span style="color:#ae81ff">6</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Here we are defining how we want to handle the shutdown -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We get a timeout value from an env variable named APP_SHUTDOWN_TIMEOUT -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> If that env variable is not found, we default to 60 seconds. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We then switch on our CtrlTypes enum and handle each value accordingly, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then return true. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">bool</span> ConsoleCtrlCheck(CtrlTypes ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> timeout = ConfigurationManager.AppSettings[<span style="color:#e6db74">&#34;APP_SHUTDOWN_TIMEOUT&#34;</span>]; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> (<span style="color:#66d9ef">string</span>.IsNullOrEmpty(timeout)) { timeout = <span style="color:#e6db74">&#34;60&#34;</span>; } -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">int</span> counter = <span style="color:#66d9ef">int</span>.Parse(timeout); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">switch</span> (ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> CtrlTypes.CTRL_SHUTDOWN_EVENT: -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] CTRL_SHUTDOWN received&#34;</span>); -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] Web Server is stopping in {counter} seconds&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">while</span> (counter &gt; <span style="color:#ae81ff">0</span>) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> Thread.Sleep(TimeSpan.FromSeconds(<span style="color:#ae81ff">1</span>)); -</span></span><span style="display:flex;"><span> counter--; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.Set(); -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span>; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span>: -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">false</span>; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Our main method is pretty standard. However, we first register a new handler (_handler), -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then pass it to to the SetConsoleCtrlHandler() method we imported from Kernel32.dll. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> The only other &#39;unique&#39; thing is the _exitEvent.WaitOne(); call defined at the bottom of main(). -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> This is necessary so that main does not immediately exit, and wait&#39;s for a signal. We defined a -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> property for this _exitEvent of type ManualResetEvent at the top of this class file. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> Main(<span style="color:#66d9ef">string</span>[] args) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> _handler += <span style="color:#66d9ef">new</span> HandlerRoutine(ConsoleCtrlCheck); -</span></span><span style="display:flex;"><span> SetConsoleCtrlHandler(_handler, <span style="color:#66d9ef">true</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = BuildStartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> WebApp.Start&lt;SelfHostStartup&gt;(startOptions); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">&#34;Press CTRL+C to stop it&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.WaitOne(); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> StartOptions BuildStartOptions() -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = <span style="color:#66d9ef">new</span> StartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted start options</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> startOptions; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>To prevent the HandlerRoutine instance from being recycled by the GC before the program exits, the HandlerRoutine must be static (as seen in the above example). This is important because if the handlerroutine is recycled before the application is finished, it will throw an error, as shown here:</p> -<pre tabindex="0"><code>A callback was made on a garbage collected delegate of type &#39;Program+HandlerRoutine::Invoke&#39;. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called. -</code></pre> - - + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. + Backup Synology NAS to Azure Storage - https://rnemeth90.github.io/posts/2022-12-25-synology-backup-to-cloud/ + http://localhost:1313/posts/2022-12-25-synology-backup-to-cloud/ Tue, 27 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-25-synology-backup-to-cloud/ - <p>I&rsquo;m not really a fan of photography. I don&rsquo;t particularly enjoy the intracies of tuning a high-end DSLR camera. Nor am I a fan of being out in nature to photograph a fall sunrise (though, that does sound peaceful). However, I do take a lot of pictures with my phone (currently, a Pixel 6). Moreso now that I am a new father. I am protective of these photos. So much that I sync them automatically from my phone to two cloud storage providers. I thought the other day, how painful it would be for either of these cloud storage providers to go offline. Though unlikely, anything is possible, right?</p> -<p>So, like any good engineer, I started looking for a solution for this concern. I have 2 Synology NAS devices here at my home. Calling a Synology a NAS is almost an insult. They are much more than that. Though they specialize in storage, they provide a plethora of apps that extend the functionality of the device. A Synology device can provide storage, email, DNS, media, etc. services though OEM and third-party apps. A single device can also link up with other devices to form a highly-available mesh of Synology services. Pretty neat for just a little black desktop box! Anyway, I&rsquo;m not a Synology salesman, so let&rsquo;s get back on track&hellip;</p> -<p>I wanted to be able to have a local copy of all of my photos (and other files) that are currently synced to the cloud. I then wanted to backup this local copy to another remote location (something like a 3-2-1 backup architecture, but not really&hellip;). Synology provides an app called Cloud Sync that can be used to sync files from a cloud storage provider like Google Photos/Drive or Microsoft OneDrive to a local device. They also provide another app called Hyper Backup that can be used to backup local files to remote storage, like an Azure Storage Account or Amazon S3 Bucket. By now, you probably get where this is going.</p> -<p>I&rsquo;m going to configure Cloud Sync to pull files down to my Synology and then use Hyper Backup to push a weekly backup to Azure Blob Storage. Let&rsquo;s dive in! -If you&rsquo;re following along, you&rsquo;ll need to install both of these apps. They are available via One-Click install in the Synology Package Center, so I won&rsquo;t cover the installation process. The setup is extremely simple as well, but I&rsquo;ll go over it just because.</p> -<p>We&rsquo;ll first setup Cloud Sync. Open Cloud Sync and click the &lsquo;+&rsquo; symbol to add a new account.</p> -<p>For my purposes, I&rsquo;m going to choose Microsoft OneDrive:</p> -<p><a href="https://rnemeth90.github.io/images/synology-cloud-sync-01.png"><img src="https://rnemeth90.github.io/images/synology-cloud-sync-01.png" alt=""></a></p> -<p>When prompted to authenticate, login to your OneDrive account. Then, configure the sync settings. You can create a name for the connection, add a local path in which to sync your files to, choose which remote folders/files to sync, the sync direction, a schedule, etc.</p> -<p><a href="https://rnemeth90.github.io/images/synology-cloud-sync-02.png"><img src="https://rnemeth90.github.io/images/synology-cloud-sync-02.png" alt=""></a></p> -<p>Click Next, and then finish the wizard. Simple.</p> -<p>Depending on the amount of files you have, you&rsquo;ll need to allow some time for your files to sync.</p> -<p>Now, we&rsquo;ll setup Hyper Backup to backup the files you sync&rsquo;d locally to remote storage. As stated previously, I&rsquo;ll be backing up my files to Azure Blob Storage. I have already created the Storage Account in Azure, and will not be covering that in this article.</p> -<p>Open Hyper Backup and click the &lsquo;+&rsquo; symbol in the lower left corner, and then click &lsquo;Data Backup Task&rsquo;. Then, choose &lsquo;Microsoft Azure&rsquo;:</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-01.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-01.png" alt=""></a> -<a href="https://rnemeth90.github.io/images/synology-hyper-backup-02.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-02.png" alt=""></a></p> -<p>On the next page, enter in your Storage Account info and then click Next. You can then choose which local folders on your Synology to backup:</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-03.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-03.png" alt=""></a></p> -<p>Click next and choose to backup application settings:</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-04.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-04.png" alt=""></a></p> -<p>On this page, we can configure the backup settings. Name the task, and configure your notification settings, schedule, compression, and encryption.</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-05.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-05.png" alt=""></a></p> -<p>On the last page, we configure our backup rotation settings. I am going to keep 31 days of backups, starting from the oldest backup. This means that at any given time I will have 31 days worth of backups in the storage account.</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-06.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-06.png" alt=""></a></p> -<p>That&rsquo;s all for configuring the backups! Very simple. Depending on how much data you have and your ISP, it may take a while to backup your files. If you configured notifications, you should receive a notification once the job is complete.</p> - - - + http://localhost:1313/posts/2022-12-25-synology-backup-to-cloud/ + I&rsquo;m not really a fan of photography. I don&rsquo;t particularly enjoy the intracies of tuning a high-end DSLR camera. Nor am I a fan of being out in nature to photograph a fall sunrise (though, that does sound peaceful). However, I do take a lot of pictures with my phone (currently, a Pixel 6). Moreso now that I am a new father. I am protective of these photos. So much that I sync them automatically from my phone to two cloud storage providers. + Building a Golang App with Github Actions - https://rnemeth90.github.io/posts/2022-12-24-gh-actions-copy/ + http://localhost:1313/posts/2022-12-24-gh-actions-copy/ Fri, 23 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-24-gh-actions-copy/ - <p>In this article, we&rsquo;ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app -written in any language though. We&rsquo;ll cover the following:</p> -<ol> -<li>What are github actions?</li> -<li>Setting up the workflow to build, test, and deploy a binary</li> -</ol> -<p>Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. They are powerful and I suggest you read more at the <a href="https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions">Official Docs</a></p> -<p>To get started, we&rsquo;ll need a golang app to build. You can use my example <a href="https://github.com/rnemeth90/golang-github-action-example">here</a> if you do not have your own.</p> -<p>The process is relatively simple. At the root of your repo, create the following directories:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>mkdir -p .github/workflows -</span></span></code></pre></div><p>Then create a yaml file (you can name it anything you want) with the content below:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">name</span>: <span style="color:#ae81ff">build-release-binary</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">run-name</span>: <span style="color:#ae81ff">Create Github Release for GoLang binary</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># anytime we push to our repo with a tag starting with the</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># letter &#39;r&#39;, we run the build</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">on</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">push</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tags</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#e6db74">&#39;r*&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">jobs</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">build</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">runs-on</span>: <span style="color:#ae81ff">ubuntu-22.04</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">permissions</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">contents</span>: <span style="color:#ae81ff">write</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># checkout our github repo to the build agent</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/checkout@v3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">fetch-depth</span>: <span style="color:#ae81ff">0</span> <span style="color:#75715e"># get all tags, needed to get git log</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">ref</span>: <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Setup the Go environment</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">setup Go Lang</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">id</span>: <span style="color:#ae81ff">build</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/setup-go@v3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">go-version</span>: <span style="color:#e6db74">&#39;^1.19.2&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Build our application</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go version -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> cd src -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [ ! -e *.mod ]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go mod init ${GITHUB_REPOSITORY} -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go mod tidy -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go build -ldflags &#34;-X main.Version=${GITHUB_REF_NAME} -X main.BuiltBy=github-actions&#34; main.go -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> execFile=$(find . -type f -executable)</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Output more values for debugging</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git version</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git branch</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git tag</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># tag our release</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">get semantic tag version and release notes from commit messages</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">id</span>: <span style="color:#ae81ff">tag</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">run</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> currentTag=${GITHUB_REF_NAME} -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> major_minor=$(echo &#34;$currentTag&#34; | cut -d&#39;.&#39; -f1-2) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> patch=$(echo &#34;$currentTag&#34; | cut -d&#39;.&#39; -f3) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> # avoid empty patch number -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> [ -n &#34;$patch&#34; ] &amp;&amp; ((patch--)) || patch=&#34;.x&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> previousTag=&#34;${major_minor}.${patch}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;&#34; &gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if git tag | grep $previousTag ; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git log -q ${currentTag}...${previousTag} --pretty=&#34;- %s&#34; -q --no-color &gt;&gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> else -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git log --pretty=&#34;- %s&#34; -q --no-color &gt;&gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> line_count=$(cat body.log | wc -l) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;currentTag=$currentTag&#34; &gt;&gt; $GITHUB_OUTPUT -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;previousTag=$previousTag&#34; &gt;&gt; $GITHUB_OUTPUT -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;line_count=$line_count&#34; &gt;&gt; $GITHUB_OUTPUT</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># create Github release with release note from file and binary asset attached</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">ncipollo/release-action@v1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">${{ env.GITHUB_REF_NAME }}</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tag</span>: <span style="color:#ae81ff">${{ env.GITHUB_REF_NAME }}</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">artifacts</span>: <span style="color:#e6db74">&#34;src/main&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">bodyFile</span>: <span style="color:#e6db74">&#34;body.log&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">token</span>: <span style="color:#ae81ff">${{ secrets.GITHUB_TOKEN }}</span> -</span></span></code></pre></div><p>Each step within this workflow starts with a hyphen. The steps are well-commented, so I will not explain them further. Once you have this file in your repo, push it to github. Then navigate to the Actions tab in your repository and you should see your workflow on the left hand side of the screen.</p> -<p><a href="https://rnemeth90.github.io/images/gh-actions-1.png"><img src="https://rnemeth90.github.io/images/gh-actions-1.png" alt=""></a></p> -<p>Now that we have our workflow setup, to get it run, all you need to do is tag and push your release to github. To do that, you can run the script in my repo <a href="https://github.com/rnemeth90/golang-github-action-example/blob/main/create_new_gh_release.sh">create_new_gh_release.sh</a> or simply run the following commands (be sure to change the tag as needed):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>newtag<span style="color:#f92672">=</span>r1.0.0 -</span></span><span style="display:flex;"><span>git tag $newtag <span style="color:#f92672">&amp;&amp;</span> git push origin $newtag -</span></span></code></pre></div><p>Now, go back to the Actions tab in your repo, and you should see the build running. Once it completes, go back to the Code tab in your github repo and you will see the release on the right hand side of the screen.</p> -<p><a href="https://rnemeth90.github.io/images/gh-actions-2.png"><img src="https://rnemeth90.github.io/images/gh-actions-2.png" alt=""></a></p> - - - + http://localhost:1313/posts/2022-12-24-gh-actions-copy/ + In this article, we&rsquo;ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app written in any language though. We&rsquo;ll cover the following: What are github actions? Setting up the workflow to build, test, and deploy a binary Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. + Chaining YAML Pipelines in Azure Devops - https://rnemeth90.github.io/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ + http://localhost:1313/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ Thu, 03 Nov 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ - <p>In this article, we&rsquo;ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. -Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to -figure this out.</p> -<p>Our two pipelines will exist in the same repository. We have a dependent-pipeline, that we only want to run once the source-pipeline is finished. This is useful if you have -some infrastructure you want to build, prior to deploying something to that infrastructure.</p> -<p>The process is actually quite simple. First, let&rsquo;s define our source pipeline:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># source-pipeline</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: <span style="color:#ae81ff">echo Hello, world!</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a one-line script&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo Add other tasks to build, test, and deploy your project. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo See https://aka.ms/yaml</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a multi-line script&#39;</span> -</span></span></code></pre></div><p>Nothing fancy here, just the build in template pipeline that Microsoft gives us for free when we create a &ldquo;Starter Pipeline&rdquo;.</p> -<p>Now, let&rsquo;s create another pipeline in the same repo that will be triggered when the pipeline above completes:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># dependent-pipeline</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">none</span> <span style="color:#75715e"># we want this pipeline to be triggered manually, not based on PR, etc.</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">pipelines</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">pipeline</span>: <span style="color:#ae81ff">source-pipeline</span> <span style="color:#75715e">#this can be anything</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">source</span>: <span style="color:#e6db74">&#39;source-pipeline&#39;</span> <span style="color:#75715e">#this needs to be the name of the &#39;source&#39; pipeline</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">trigger</span>: <span style="color:#66d9ef">true</span> <span style="color:#75715e"># Run dependent-pipeline pipeline when any run of security-lib-ci completes</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: <span style="color:#ae81ff">echo Hello, world!</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a one-line script&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo Add other tasks to build, test, and deploy your project. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo See https://aka.ms/yaml</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a multi-line script&#39;</span> -</span></span></code></pre></div><p>The resources block above defines our dependency. You want to be sure to configure the trigger of the dependent pipeline appropriately as well.</p> -<p>There are several options for fine-tuning this process. See the office Microsoft documentation below:</p> -<p><a href="https://learn.microsoft.com/en-us/azure/devops/pipelines/process/pipeline-triggers?view=azure-devops">Link to the Microsoft Docs</a></p> - - - + http://localhost:1313/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ + In this article, we&rsquo;ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to figure this out. Our two pipelines will exist in the same repository. + Update Azure Devops SPN Secret - https://rnemeth90.github.io/posts/2022-09-12-update-azure-devops-spn-secret/ + http://localhost:1313/posts/2022-09-12-update-azure-devops-spn-secret/ Mon, 12 Sep 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-09-12-update-azure-devops-spn-secret/ - <p>If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal.</p> -<p>In this article, I&rsquo;ll show you two methods for updating a secret for a service principal prior to expiration.</p> -<h1 id="update-the-secret-via-the-azure-devops-portal" >Update the secret via the Azure Devops Portal: -<span> - <a href="#update-the-secret-via-the-azure-devops-portal"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h1><ul> -<li>Go to &ldquo;Service Connections&rdquo; in the Azure Devops portal</li> -<li>Find the SPN you want to update, then click &ldquo;Manage Service Principal&rdquo;</li> -<li>Then on the service principal page, click Certificates &amp; Secrets</li> -<li>Create a &ldquo;New Client Secret&rdquo;, take note of the value</li> -<li>Delete the &lsquo;old&rsquo; secret</li> -<li>Return to the Service Connection in the Azure Devops portal</li> -<li>Click Edit - click the verify button. It should tell you the client certificate has expired</li> -<li>Now you need to make an arbitrary change and save it. I just type a character in the optional description and save.</li> -<li>Now edit again and click verify, it will now pick up the new client secret and all is happy.</li> -<li>You can now remove whatever you added to the description.</li> -</ul> - - - + http://localhost:1313/posts/2022-09-12-update-azure-devops-spn-secret/ + If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal. In this article, I&rsquo;ll show you two methods for updating a secret for a service principal prior to expiration. Update the secret via the Azure Devops Portal: Link to heading Go to &ldquo;Service Connections&rdquo; in the Azure Devops portal Find the SPN you want to update, then click &ldquo;Manage Service Principal&rdquo; Then on the service principal page, click Certificates &amp; Secrets Create a &ldquo;New Client Secret&rdquo;, take note of the value Delete the &lsquo;old&rsquo; secret Return to the Service Connection in the Azure Devops portal Click Edit - click the verify button. + Use “replace” in go.mod to Point to a Local Module - https://rnemeth90.github.io/posts/2022-09-06-go-mod-replace-copy/ + http://localhost:1313/posts/2022-09-06-go-mod-replace-copy/ Tue, 06 Sep 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-09-06-go-mod-replace-copy/ - <p>If you want to the local version of a dependency in Go rather than one in a remote repository, use the <em>replace</em> keyword.</p> -<p>The replace line goes above your require statements, like so:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> module github.com/rnemeth90/foo -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> replace github.com/rnemeth90/bar <span style="color:#f92672">=</span>&gt; /Users/rnemeth90/Projects/bar -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> require <span style="color:#f92672">(</span> -</span></span><span style="display:flex;"><span> github.com/rnemeth90/bar v1.0.0 -</span></span><span style="display:flex;"><span> <span style="color:#f92672">)</span> -</span></span></code></pre></div><p>Now when you compile this module <em>go build</em> or <em>go install</em>, it will use your local code rather than the remote dependency.</p> -<p>According to the docs, you do need to make sure that the code you’re pointing to also has a <strong>go.mod</strong> file:</p> -<blockquote> -<p><strong>Note</strong>: if the right-hand side of a <code>replace</code> directive is a filesystem path, then the target must have a <code>go.mod</code> file at that location. If the <code>go.mod</code> file is not present, you can create one with <code>go mod init</code>.</p> -<p><a href="https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive">https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive</a></p> -</blockquote> -<p>You can also create this line from the command line using the <strong>go mod edit</strong> command.</p> -<pre><code>$ go mod edit -replace github.com/rnemeth90/bar=/Users/rnemeth90/Projects/bar -</code></pre> -<p>Following the <strong>-replace</strong> is first what you want to replace, then an equals sign, then what you’re replacing it with.</p> -<p>Hopefully this helps someone who was stuck with this like me 🙂</p> - - - + http://localhost:1313/posts/2022-09-06-go-mod-replace-copy/ + If you want to the local version of a dependency in Go rather than one in a remote repository, use the replace keyword. The replace line goes above your require statements, like so: module github.com/rnemeth90/foo replace github.com/rnemeth90/bar =&gt; /Users/rnemeth90/Projects/bar require ( github.com/rnemeth90/bar v1.0.0 ) Now when you compile this module go build or go install, it will use your local code rather than the remote dependency. According to the docs, you do need to make sure that the code you’re pointing to also has a go. + Powershell for Devops - Querying REST APIs with Powershell - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ Thu, 04 Aug 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ - <p>This will be a short post on querying REST APIs with Powershell.</p> -<p>It&rsquo;s hard to argue that REST APIs are the predominant technology for interacting -with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) -product without having to go through the exercise of a more complicated integration. REST APIs communicate -in a common format, typically JSON. However, most will allow us to choose the response format by specifying an -option in the &lsquo;Accept&rsquo; header. Most languages provide a native method for interacting with -REST APIs. This objective for this post is to show you how simple this is with Powershell.</p> -<p>To get started, we&rsquo;ll need a public API to interact with. I&rsquo;m going to use <a href="https://icanhazdadjoke.com/">https://icanhazdadjoke.com/</a>, because -there is no authentication and no rate-limiting (two concepts we will cover in another post).</p> -<p>Calling the API is extremely simple:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -</span></span></code></pre></div><p>However, this results in the content being returned as plain text. This isn&rsquo;t ideal.</p> -<p>Let&rsquo;s pass the &lsquo;Accept&rsquo; header to tell the API the format we are expecting to be returned:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers -</span></span></code></pre></div><p>Output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>[<span style="color:#ae81ff">15</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">04</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">34</span>] C:\..\..\rnemeth90.github.io on <span style="color:#960050;background-color:#1e0010"></span>main <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#ae81ff">+1</span> <span style="color:#960050;background-color:#1e0010">❯</span> Invoke-RestMethod -Uri $url -Method Get -Headers $headers -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>id joke status -</span></span><span style="display:flex;"><span>-- ---- ------ -</span></span><span style="display:flex;"><span>3LmyXvsPfqc I don<span style="color:#e6db74">&#39;t trust stairs. They&#39;</span>re always up to something. <span style="color:#ae81ff">200</span> -</span></span></code></pre></div><p>That looks a little better. For those of you familiar with Powershell, the output above probably -looks completely normal. But for those not-so-familiar with Powershell, or those expecting -more of a &lsquo;json-esk&rsquo; output, this may look a bit&hellip; weird.</p> -<p>Powershell is an object oriented language. <strong>Everything is an object</strong> in Powershell, even the response -of this request. What you see in the output is simply the properties of the object.</p> -<p>Luckily Powershell provides us with a cmdlet to convert an object into json (aptly named: ConvertTo-Json). We can use it like this:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers | ConvertTo-Json -</span></span></code></pre></div><p>Here we are piping the output from Invoke-RestMethod to ConvertTo-Json. Pretty neat!</p> -<p>Output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>[<span style="color:#ae81ff">15</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">04</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">35</span>] C:\..\..\rnemeth90.github.io on <span style="color:#960050;background-color:#1e0010"></span>main <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#ae81ff">+1</span> <span style="color:#960050;background-color:#1e0010">❯</span> Invoke-RestMethod -Uri $url -Method Get -Headers $headers | Convertto-json -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;id&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#e6db74">&#34;AAdFBXnGlyd&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;joke&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#e6db74">&#34;If you walk into a forest and cut down a tree, but the tree doesn&#39;t understand why you cut it down, do you think it&#39;s stumped?&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;status&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#ae81ff">200</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Now, that looks more normal.</p> -<p>There is much more we can do with Invoke-RestMethod. The &lsquo;Method&rsquo; parameter of this cmdlet accepts any of the common -HTTP methods (GET, PUT, PATCH, DELETE, POST, HEAD). You can also specify other headers and a body (using the -body parameter).</p> -<p>Both of these parameters accept dictionaries:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Host&#39;</span> = <span style="color:#e6db74">&#39;MyServer&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>$body = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Eat&#39;</span> = <span style="color:#e6db74">&#39;Pizza&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers -Body $body | ConvertTo-Json -</span></span></code></pre></div><p>Unfortunately I won&rsquo;t be able to show the other HTTP methods, as this API only supports GET requests. So that&rsquo;s all for now.</p> - - - + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ + This will be a short post on querying REST APIs with Powershell. It&rsquo;s hard to argue that REST APIs are the predominant technology for interacting with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) product without having to go through the exercise of a more complicated integration. REST APIs communicate in a common format, typically JSON. However, most will allow us to choose the response format by specifying an option in the &lsquo;Accept&rsquo; header. + Reading Json Files with Go - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ + http://localhost:1313/posts/2022-07-21-reading-json-files-with-go/ Thu, 21 Jul 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ - <p>JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting -with it, and most public APIs accept JSON in HTTP requests.</p> -<p>In this post, we&rsquo;ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the -JSON data within the file into a memory structure.</p> -<p>Let&rsquo;s assume we have the following JSON data representing an employee:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">1</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Steve&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Rogers&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Captain America&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Department&#34;</span>: <span style="color:#e6db74">&#34;Avengers&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>We need a way of representing this data in memory when decoding it from JSON. For this, we will need to create a struct:</p> -<p>We will build up our go module as we progress through the article</p> -<p>Let&rsquo;s start:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#75715e">// main.go -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> ( -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;encoding/json&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;fmt&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;io/ioutil&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;log&#34;</span> -</span></span><span style="display:flex;"><span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">// Hero represents an hero -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// ALL fields must be exportable! Otherwise the JSON parsing will fail. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Hero</span> <span style="color:#66d9ef">struct</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Id</span> <span style="color:#66d9ef">int</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">FirstName</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">LastName</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Alias</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Group</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() { -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Here we set the log prefix. When reading stack traces, this makes it easier to know -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// where a failure occurred. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">SetPrefix</span>(<span style="color:#e6db74">&#34;main(): &#34;</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// We first need to load the JSON file into memory -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">content</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">ioutil</span>.<span style="color:#a6e22e">ReadFile</span>(<span style="color:#e6db74">&#34;./heros.json&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#e6db74">&#34;Error opening the file: &#34;</span>, <span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Now we parse the JSON data into a memory structure. We know our JSON file will have more than one hero object, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// so we&#39;ll use make() to create a []Hero slice. Since go is a pass-by-value language, we will then use the address-of -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// operator (&amp;) to unmarshal our json data into the heros slice -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">heros</span> <span style="color:#f92672">:=</span> make([]<span style="color:#a6e22e">Hero</span>, <span style="color:#ae81ff">5</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">json</span>.<span style="color:#a6e22e">Unmarshal</span>(<span style="color:#a6e22e">content</span>, <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">heros</span>) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#e6db74">&#34;Error occurred during unmarshal: &#34;</span>, <span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// now we can read/interact with the data. We&#39;ll loop over the array -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// and print the values in memory -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; len(<span style="color:#a6e22e">heros</span>); <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">Id</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">FirstName</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">LastName</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">Group</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Create a file named employees.json with similar data:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>[ -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">1</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Steve&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Rogers&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Captain America&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;group&#34;</span>: <span style="color:#e6db74">&#34;Avengers&#34;</span> -</span></span><span style="display:flex;"><span> }, -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">2</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Clark&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Kent&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Superman&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;group&#34;</span>: <span style="color:#e6db74">&#34;Justice League&#34;</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>] -</span></span></code></pre></div><p>Now, we can run our main.go file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>11:40:47 ryan@xerxes json → go run main.go -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>Steve -</span></span><span style="display:flex;"><span>Rogers -</span></span><span style="display:flex;"><span>Avengers -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span>Clark -</span></span><span style="display:flex;"><span>Kent -</span></span><span style="display:flex;"><span>Justice League -</span></span><span style="display:flex;"><span>11:40:49 ryan@xerxes json -</span></span></code></pre></div><p>Pretty simple! That&rsquo;s why I love go. We accomplished all of this with ~50 lines of code. -Doing something similar in asp.net project would easily double that count and involve creating -multiple files! (nothing against asp.net or c#, I think c# is a great language and use it daily)</p> -<p>Now, &lsquo;go&rsquo; try this!</p> - - - + http://localhost:1313/posts/2022-07-21-reading-json-files-with-go/ + JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting with it, and most public APIs accept JSON in HTTP requests. In this post, we&rsquo;ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the JSON data within the file into a memory structure. + AKS Scale Down Mode - https://rnemeth90.github.io/posts/2022-07-19-aks-scale-down-mode/ + http://localhost:1313/posts/2022-07-19-aks-scale-down-mode/ Tue, 19 Jul 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-07-19-aks-scale-down-mode/ - <p>By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete <em>or</em> deallocate nodes.</p> -<p>Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. However, you will still need to pay for any storage that the node is using. Having persistent storage also means that any container images that were cached on the node will still be there when the node starts back up. This can be a major performance benefit if you are using Windows containers because the images for these containers are typically very large.</p> -<p>Scale down mode can be configured in several ways. Here, we will look at configuring it via the Azure CLI and Terraform.</p> -<p>Azure CLI:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>az aks nodepool update --scale-down-mode Deallocate --name nplinux01 --cluster-name myAKSCluster --resource-group myResourceGroup -</span></span></code></pre></div><p>Terraform:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-hcl" data-lang="hcl"><span style="display:flex;"><span><span style="color:#66d9ef">resource</span> <span style="color:#e6db74">&#34;azurerm_kubernetes_cluster_node_pool&#34; &#34;nodepool&#34;</span> { -</span></span><span style="display:flex;"><span> name <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;nplinux01&#34;</span> -</span></span><span style="display:flex;"><span> kubernetes_cluster_id <span style="color:#f92672">=</span> <span style="color:#66d9ef">azurerm_kubernetes_cluster</span>.<span style="color:#66d9ef">example</span>.<span style="color:#66d9ef">id</span> -</span></span><span style="display:flex;"><span> vm_size <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Standard_DS2_v2&#34;</span> -</span></span><span style="display:flex;"><span> node_count <span style="color:#f92672">=</span> <span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span> scale_down_mode <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Deallocate&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> tags <span style="color:#f92672">=</span> { -</span></span><span style="display:flex;"><span> Environment <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;lab&#34;</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><em>At the time of this writing, Terraform does not support configuring scale-down mode for the default AKS node pool.</em> -<em>Node pools using ephemeral disks do not support &lsquo;deallocate&rsquo; mode</em></p> - - - + http://localhost:1313/posts/2022-07-19-aks-scale-down-mode/ + By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete or deallocate nodes. Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. + Scheduled Kubernetes Worker Node Maintenance with Kured - https://rnemeth90.github.io/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ + http://localhost:1313/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ Fri, 15 Jul 2022 18:18:50 +0000 - - https://rnemeth90.github.io/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ - <p>If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this?</p> -<p>Weaveworks created a great tool for simplifying these steps: Kured (the <em><strong>Ku</strong>bernetes <strong>Re</strong>boot <strong>D</strong>aemon</em>). Let’s start by deploying Kured to our cluster.</p> -<p>Kured can be deployed in one of several ways. In this article, we’ll focus on deploying it via Helm. This is the simplest and quickest way to get it running in our cluster.</p> -<p>Follow these steps to install the Helm chart:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># 1) Add the Kured Helm repository</span> -</span></span><span style="display:flex;"><span>helm repo add kured https://weaveworks.github.io/kured -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 2) Update your local Helm chart repository cache</span> -</span></span><span style="display:flex;"><span>helm repo update -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 3) Create a dedicated namespace where you would like to deploy kured</span> -</span></span><span style="display:flex;"><span>kubectl create namespace kured -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 4) Install kured in that namespace with Helm 3 (only on Linux nodes)</span> -</span></span><span style="display:flex;"><span>helm install kured kured/kured --namespace kured --set nodeSelector.<span style="color:#e6db74">&#34;kubernetes\.io/os&#34;</span><span style="color:#f92672">=</span>linux -</span></span></code></pre></div><p>If all went well with the command above, that’s it, you’re done! Have a nice day! 🙂</p> -<p>If you want to test Kured, login to one of your Linux nodes, and install some patches with your package manager of choice (any patch that requires a reboot, typically patches that modify kernel headers). Then, check for a file named ‘reboot-required’ in /var/run:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>ls -lisa /var/run/reboot-required -</span></span></code></pre></div><p>If you installed patches, and this file does not exist, none of your patches require a reboot. We can still fake the system into thinking a reboot is required by manually creating the ‘reboot-required’ file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo touch /var/run/reboot-required -</span></span></code></pre></div><p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-1.png" alt=""></p> -<p>Then, we’ll use Kubetail to tail the logs of all our Kured pods:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubetail -label kured --namespace kured -</span></span></code></pre></div><p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-1024x749.png" alt=""></p> -<p>By default, Kured checks for the existence of the sentinel file every 60 minutes. However, this behavior can be changed. See the github repo for more info:</p> -<p><img src="https://github.com/weaveworks/kured#reboot-sentinel-file--period" alt="weaveworks/kured: Kubernetes Reboot Daemon"></p> -<p>Scheduling on the node should be disabled if you are within the Kured schedule</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-2.png" alt=""></p> -<p>Now that the node is cordoned off, running pods on the node are drained, and the node is rebooted.</p> -<p>That’s it for this article. Have a great day!</p> - - - + http://localhost:1313/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ + If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this? Weaveworks created a great tool for simplifying these steps: Kured (the Kubernetes Reboot Daemon). + Running Docker in WSL v1 - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ Sun, 26 Jun 2022 15:00:28 +0000 - - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ - <p>I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate.</p> -<p>Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. I receive this nice message:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ docker -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>The command <span style="color:#e6db74">&#39;docker&#39;</span> could not be found in this WSL <span style="color:#ae81ff">1</span> distro. -</span></span><span style="display:flex;"><span>We recommend to convert this distro to WSL <span style="color:#ae81ff">2</span> and activate -</span></span><span style="display:flex;"><span>the WSL integration in Docker Desktop settings. -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>See https://docs.docker.com/docker-for-windows/wsl/ <span style="color:#66d9ef">for</span> details. -</span></span></code></pre></div><p>So I’m in somewhat of a catch-22 here…</p> -<p>To work around this problem until a proper solution is found, I was able to get Docker working with WSL v1.</p> -<p>If you happen to be having a similar issue (and it seems like quite a few people are, considering the number of Github posts I found), just follow these steps:</p> -<ul> -<li>Expose the Docker daemon in docker desktop settings:</li> -</ul> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/02/image-10-1024x585.png"></a></p> -<p>Install the stand-alone Docker client in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ tar zxvf docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ cd docker -</span></span></code></pre></div><p>Set the default Docker daemon in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>export DOCKER_HOST<span style="color:#f92672">=</span>tcp://localhost:2375 -</span></span></code></pre></div><p>Verify you can connect to Docker running on Windows from within WSL:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>./docker info -</span></span></code></pre></div><p>This is also beneficial in that you only have one Docker host to manage your containers, network, etc., rather than two.</p> - - - + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ + I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. + EF Core &#8211; Unable to create an object of type DbContext - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ Sun, 12 Jun 2022 13:58:52 +0000 - - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ - <p>This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it!</p> -<p>When running EF Core migrations in a solution, you may come across this error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-1-1024x142.png"></a></p> -<p>There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio.</p> -<p>To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-2.png"></a></p> -<p>If you are using clean architecture, or some other architecture that has your startup context and your dbContext in different projects, you will need to set your startup project to your runtime, and the ‘Default Project’ in the package manager console to the project containing your dbContext.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-3-1024x493.png"></a></p> - - - + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it! When running EF Core migrations in a solution, you may come across this error: There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio. To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’. + Remove Kubernetes Namespace Stuck in the Terminating State - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ Sat, 04 Jun 2022 18:29:41 +0000 - - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ - <p>In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state.</p> -<p>A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. One day, you decide you no longer want this blog, so you plan to delete it. Rather than tediously deleting all of the various entities associated with this blog, you can delete the namespace that contains these entities. This will essentially ‘cascade delete’ the resources within the namespace as well.</p> -<p>After deleting the namespace for your blog, you notice that it still exists, but the state of it is ‘Terminating’, and it has been like this for a long time (hours or maybe even days).</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/06/image.png"></a></p> -<p>Kubernetes will occassionally fail to delete third-party resources when deleting a namespace, causing the namespace to linger. This can happen if the third-party API managing the resource is not responding to requests. To verify if any of these resources still exist, use this command:</p> -<pre tabindex="0"><code>kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get --show-kind --show-all --ignore-not-found -n &lt;terminating-namespace&gt; -</code></pre><p>If you happen to see any resources in the output, you can try force deleting them and then try to delete the namespace again.</p> -<p>In my experience, the majority of the time you will not find any resources still hanging around. Rather, the namespace will be completely empty. What is going on here?</p> -<p>Let’s take a look at the namespace:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ae81ff">$ kubectl get namespace darn-c101 -o yaml</span> -</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Namespace</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">annotations</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">kubectl.kubernetes.io/last-applied-configuration</span>: <span style="color:#ae81ff">|</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">kubernetes.io/metadata.name</span>: <span style="color:#ae81ff">darn-c101</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">finalizers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">kubernetes</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">status</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">conditions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">lastTransitionTime</span>: <span style="color:#e6db74">&#34;2022-06-01T19:05:31Z&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">message: &#39;Some content in the namespace has finalizers remaining</span>: <span style="color:#ae81ff">darn-c101.geekyryan.io/finalizer in 1 resource instances&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">reason</span>: <span style="color:#ae81ff">SomeFinalizersRemain</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">status</span>: <span style="color:#e6db74">&#34;True&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">NamespaceFinalizersRemaining</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">phase</span>: <span style="color:#ae81ff">Terminating</span> -</span></span></code></pre></div><p>Notice the inclusion of the finalizers field in the above JSON. Some namespaces have a finalizer defined under spec.</p> -<p>A finalizer is a special metadata key that tells Kubernetes to wait until a specific condition is met before it fully deletes a resource. Much like a finalizer in the .NET framework (does Java have those too? 😀 )</p> -<p>So when you run a command like <code>kubectl delete namespace &lt;namespace&gt;</code>, Kubernetes checks for a finalizer in the <code>metadata.finalizers</code> field. If the resource defined in the finalizer cannot be deleted, then the namespace is not deleted either. This puts the namespace into a perpetual terminating state and is never actually deleted.</p> -<p>When an object has been terminating for an excessive time, check its finalizers by inspecting the <code>metadata.finalizers</code> field in its YAML.</p> -<p>So we now know what the problem is. How can we solve it? Well, it’s actually quite simple. If you are using bash, use this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> -</span></span><span style="display:flex;"><span>namespaces<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>kubectl get ns --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Terminating -o jsonpath<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;{range .items[*]}{.metadata.name}{&#34;\n&#34;}{end}&#39;</span><span style="color:#66d9ef">)</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -z <span style="color:#e6db74">&#34;</span>$namespaces<span style="color:#e6db74">&#34;</span><span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">&#34;No namespaces to delete.&#34;</span> -</span></span><span style="display:flex;"><span> exit -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> namespace in $namespaces -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">do</span> -</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">&#34;[Removing Namespace]: </span>$namespace<span style="color:#e6db74">&#34;</span> -</span></span><span style="display:flex;"><span> kubectl get namespace $namespace -o json | tr -d <span style="color:#e6db74">&#34;\n&#34;</span> | sed <span style="color:#e6db74">&#34;s/\&#34;finalizers\&#34;: \[[^]]\+\]/\&#34;finalizers\&#34;: []/&#34;</span> | kubectl replace --raw /api/v1/namespaces/$namespace/finalize -f - &gt; /dev/null 2&gt;&amp;<span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">done</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span> -</span></span></code></pre></div><p><a href="https://gist.github.com/rnemeth90/e83bb4c8808f0d28412cb40edb2487d3">Delete Terminating Kubernetes Namespaces with Bash (github.com)</a></p> -<p>It will search for any namespace that is stuck in the terminating state and forcefully remove it by removing the finalizers field and then using <code> kubectl replace</code> to commit the change back to the Kube API.</p> -<p>If you prefer Powershell, you can use this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$terminatingNamespaces = kubectl get ns --field-selector=status.phase==Terminating -o jsonpath=<span style="color:#e6db74">&#34;{range .items[*]}{.metadata.name}{&#39;\n&#39;}{end}&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($ns <span style="color:#66d9ef">in</span> $terminatingNamespaces) { -</span></span><span style="display:flex;"><span> Write-Verbose <span style="color:#e6db74">&#39;[FOUND]: Forcefully removing $ns&#39;</span> -</span></span><span style="display:flex;"><span> $jsonObj = kubectl get namespace $ns -o json | ConvertFrom-Json | foreach-object { $_.spec.finalizers = @(); $_ } | -</span></span><span style="display:flex;"><span> convertto-json | kubectl replace --raw /api/v1/namespaces/$namespace/finalize <span style="color:#f92672">-f</span> - -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><a href="https://gist.github.com/rnemeth90/19d7de622a5009c1cf908c5d4deb5358">Delete Terminating Kubernetes Namespaces with Powershell (github.com)</a></p> -<p>It does the same thing as the bash script, just in more of a Window-zy way.</p> -<p>It’s that simple. I hope this was helpful. If you have any questions, comments, or concerns, please feel free to reach out.</p> - - - + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state. A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. + Injecting multiple Kubernetes volumes to the same directory in a pod - https://rnemeth90.github.io/posts/2022-04-30-injecting-multiple-kubernetes-volumes-to-the-same-directory-in-a-pod/ + http://localhost:1313/posts/2022-04-30-injecting-multiple-kubernetes-volumes-to-the-same-directory-in-a-pod/ Sat, 30 Apr 2022 14:21:05 +0000 - - https://rnemeth90.github.io/posts/2022-04-30-injecting-multiple-kubernetes-volumes-to-the-same-directory-in-a-pod/ - <p>We can inject configuration into containers using Kubernetes config maps and secrets. These objects can be consumed by a pod as environment variables, command-line arguments, or as configuration files mounted in a volume. For the subject of this article, we will focus on mounting multiple config maps/secrets into a single directory on a pod.</p> -<p>Mounting a configmap or secret in a Volume is relatively straightforward (for anyone familiar with Kubernetes primitives). Take for example the following deployment definition:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ConfigMap</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">application.properties</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> greeting=Hello -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> name=World</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>--- -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Secret</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-credentials</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">credentials.properties</span>: <span style="color:#ae81ff">&lt;base64 goes here&gt;</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">type</span>: <span style="color:#ae81ff">Opaque</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>--- -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Deployment</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">matchLabels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">template</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">busybox:latest</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">command</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">/bin/sh</span> -</span></span><span style="display:flex;"><span> - -<span style="color:#ae81ff">c</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">sleep 5000</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/config/application.properties</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readOnly</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-credentials-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/config/credentials.properties</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readOnly</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">configMap</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-credentials-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">secret</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">secretName</span>: <span style="color:#ae81ff">hello-world-credentials</span> -</span></span></code></pre></div><p>When this deployment is created, we see two directories are created in this pod (one for the configMap, and one for the secret). How can we mount these as two <em>files</em> in the ‘config’ directory, rather than two individual directories?</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/04/image.png"></a></p> -<p>The ~VolumeMounts~ directive within the container spec of the deployment has an optional (less-known) parameter named ‘subPath’. By using this parameter, we can mount a configMap and secret in the same directory within a pod.</p> -<p>Let’s focus on the following deployment spec:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ConfigMap</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">application.properties</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> greeting=Hello -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> name=World</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>--- -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Secret</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-credentials</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">credentials.properties</span>: <span style="color:#ae81ff">&lt;base64 goes here&gt;</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">type</span>: <span style="color:#ae81ff">Opaque</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>--- -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Deployment</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">matchLabels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">template</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">busybox:latest</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">command</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">/bin/sh</span> -</span></span><span style="display:flex;"><span> - -<span style="color:#ae81ff">c</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">sleep 5000</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/config/application.properties</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">subPath</span>: <span style="color:#ae81ff">application.properties</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readOnly</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-credentials-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/config/credentials.properties</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">subPath</span>: <span style="color:#ae81ff">credentials.properties</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readOnly</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">configMap</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-config</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">hello-world-credentials-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">secret</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">secretName</span>: <span style="color:#ae81ff">hello-world-credentials</span> -</span></span></code></pre></div><p>Now, if we deploy this, we can see that we have two files in the ‘config’ directory of the pod, rather than a subdirectory for each config/secret:</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/04/image-1.png"></a></p> -<p>In this example, the key application.properties from the configuration map will be mounted to a file with the same name under /config/, and the secret value credentials.properties will be mounted to a second file under that directory. Both files will be read-only to the application.</p> - - - + http://localhost:1313/posts/2022-04-30-injecting-multiple-kubernetes-volumes-to-the-same-directory-in-a-pod/ + We can inject configuration into containers using Kubernetes config maps and secrets. These objects can be consumed by a pod as environment variables, command-line arguments, or as configuration files mounted in a volume. For the subject of this article, we will focus on mounting multiple config maps/secrets into a single directory on a pod. Mounting a configmap or secret in a Volume is relatively straightforward (for anyone familiar with Kubernetes primitives). + Kubernetes Storage Simplified - https://rnemeth90.github.io/posts/2022-03-01-kubernetes-storage-simplified/ + http://localhost:1313/posts/2022-03-01-kubernetes-storage-simplified/ Tue, 01 Mar 2022 08:37:58 +0000 - - https://rnemeth90.github.io/posts/2022-03-01-kubernetes-storage-simplified/ - <p>In this blog post, we will attempt to explain the current storage options that exist in Kubernetes. If you are new to Kubernetes, learning about its capabilities of managing the application state can be a daunting task.</p> -<p>Container images are built-in layers, with the runtime layer being writable. However, any files on this writable layer are only available for the container’s lifetime. We can mount a volume to a directory inside the container to have persistent data.</p> -<p>Kubernetes storage uses the concepts of volumes. Ephemeral volumes are called volumes and only last the lifetime of a pod, and “persistent volumes” are used for long-term storage. A typical use case for Ephemeral volumes is storing logs that are not sent to stdout.</p> -<p>Mounting a persistent volume inside a container allows you to persist the state of your application long after the container is terminated. Persistent volumes can also take advantage of the typical storage idiosyncrasies such as backup, compression, and encryption.</p> -<h2 id="persistent-volumes" >Persistent Volumes -<span> - <a href="#persistent-volumes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Kubernetes has several types of persistent volumes. At its core, a persistent volume is simply a directory mounted inside a pod. How that volume is created, the configuration options and the medium that backs it are all determined by the type of volume created.</p> -<p>There are several types of volumes available, too many to list here. You may commonly see some volume types: NFS, iSCSI, hostpath, and local. If your Kubernetes cluster exists in a cloud environment such as Azure or AWS, other volume types are available to you (azureDisk, azureFile, and awsElasticBlockStore, respectively). A complete list of types can be found here:</p> -<p><a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes">https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes</a></p> -<p>Creating a persistent volume is generally a simple task. The first step is determining the type of volume to create. In this post, we will cover creating a local volume. A local volume represents a disk, partition, or directory shared from a node. Local volumes are subject to the availability of the underlying node, meaning that if the node is offline, the volume is also offline and will not be accessible by any pod. Because of this, local volumes should not be used in production.</p> -<p>A persistent volume can only be created using a declarative approach. To create a persistent local volume, use the following YAML definition:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolume</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">example-pv</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">capacity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMode</span>: <span style="color:#ae81ff">Filesystem</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteOnce</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeReclaimPolicy</span>: <span style="color:#ae81ff">Delete</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">local-storage</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">local</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># the path to the volume or directory on the node</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/mnt/disks/ssd1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeAffinity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">required</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeSelectorTerms</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">matchExpressions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">key</span>: <span style="color:#ae81ff">kubernetes.io/hostname</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">operator</span>: <span style="color:#ae81ff">In</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">values</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># name of the node sharing the volume</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">node01</span> -</span></span></code></pre></div><p>When creating a persistent volume of this type, you must specify a node affinity. This ensures that the Kubernetes scheduler schedules any pods requesting access to this volume on the correct node. For example, any pod requesting access to the persistent volume named ‘example-PV will only be scheduled on the node ‘node01’.</p> -<p>Let’s dive into this persistent volume spec a bit more:</p> -<p>You can change the capacity of the persistent volume by updating:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">capacity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span></code></pre></div><p>The accessModes will be determined by the storage provider being used. There are generally 3 access modes available: ReadWriteOnce, ReadWriteMany, and ReadOnlyMany.</p> -<ul> -<li>ReadWriteOnce – The volume can be mounted as read-write by a single node</li> -<li>ReadWriteMany – The volume can be mounted as read-write by many nodes</li> -<li>ReadOnlyMany – The volume can be mounted as read-only by many nodes</li> -</ul> -<p>The “persistentVolumeReclaim” policy determines what happens to a persistent volume when it is no longer mounted by any pods (i.e., there are no claims to it, more on this later). There are three options available for the reclaim policy:</p> -<ul> -<li>Retain – The persistent volume is kept as-is. It must be manually removed when no longer needed.</li> -<li>Recycle – The persistent volume is scrubbed and can be re-used by other pods</li> -<li>Delete – The persistent volume is deleted.</li> -</ul> -<p>Currently, only NFS and hostPath volumes support recycling. Cloud storage providers (Azure, AWS, and GCE) support deletion.</p> -<p>The other aspects of this spec are unique to the volume being used. Since we are using a local volume here, we must specify the path to the directory or volume on the host and the host which is sharing the directory or volume:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span> <span style="color:#f92672">local</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># the path to the volume or directory on the node</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/mnt/disks/ssd1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeAffinity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">required</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeSelectorTerms</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">matchExpressions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">key</span>: <span style="color:#ae81ff">kubernetes.io/hostname</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">operator</span>: <span style="color:#ae81ff">In</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">values</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># name of the node sharing the volume</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">node01</span> -</span></span></code></pre></div><h2 id="ephemeral-volumes" >Ephemeral Volumes -<span> - <a href="#ephemeral-volumes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Note: The Kubernetes documentation recognizes configMaps and Secrets as ephemeral volumes. However, in this article, we will only discuss ephemeral volumes used for data storage (emptyDir volumes).</p> -<p>Ephemeral volumes are defined within the context of a pod. This means that you cannot create an ephemeral volume on its own. Instead, define the ephemeral volume in the pod or a deployment spec.</p> -<p>Ephemeral volumes are useful in a few scenarios:</p> -<ol> -<li>You want to share data between multiple containers in a pod</li> -<li>You want to cache temporary information such as log files</li> -<li>You need scratch space to store data before it is processed by another container or pod</li> -</ol> -<p>If one of the containers in the pod happens to restart, data on the ephemeral volume will still exist; as long as one of the containers is mounting, it stays online. In other words, if a pod mounting the ephemeral volume is removed from a node, data on the ephemeral volume is lost. However, if a pod crashes, the data on the volume remains intact.</p> -<p>As stated previously, creating an ephemeral volume is done as part of the pod or deployment template:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/cache</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">emptyDir</span>: {} -</span></span></code></pre></div><p>If the template, you add a volume of type ’emptyDir’ in the ‘volumes’ spec and name it. You can mount this volume in any container in the pod. The volume does not have to be mounted to the same directory in each container.</p> -<h2 id="persistent-volume-claims" >Persistent Volume Claims -<span> - <a href="#persistent-volume-claims"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>A persistentVolumeClaim (often referred to as a ‘PVC’) is used by a pod to create a ‘claim’ on storage. Using a PVC, a pod can mount multiple persistent volumes simultaneously to any directory in the pod.</p> -<p>PersistentVolumeClaim’s are a Kubernetes primitive that can be deployed from a manifest:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fast-storage-pvc</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMode</span>: <span style="color:#ae81ff">Filesystem</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">8Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">fast</span> -</span></span></code></pre></div><p>Most of the options in the manifest above seem pretty obvious. The volumeMode specifies whether to consume the persistent volume as a FileSystem or block device. The resources section helps specify the amount of storage you require (8Gi in this example). We will cover the storageClassName in the next section. Finally, the accessModes are identical to those described above in the Persistent Volumes section.</p> -<p>Pods access a volume by using the persistentVolumeClaim as volume. Claims must exist in the same namespace as the pod using the claim. The controller finds the claim in the pods’ namespace and uses it to find a persistent volume capable of backing the claim. The volume is then mounted on the host and attached to the pod.</p> -<p>To create a pod that utilizes a PVC, use the following yaml definition:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/mnt/share</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span></code></pre></div><h2 id="storage-classes" >Storage Classes -<span> - <a href="#storage-classes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>In this article, we will only be referencing Kubernetes storage classes with respect to dynamic provisioners. If you would like to learn more, please reference the Kubernetes docs:</p> -<p><a href="https://bit.ly/3ruJD2A">https://bit.ly/3ruJD2A</a></p> -<p>Storage Classes have many uses. Kubernetes is unopinionated about what a storage class represents. They can be used to represent different characteristics of storage (performance, compression method, file system modes, etc.). Storage Classes can also be used to provision persistent volumes dynamically, which will be the focus of this article.</p> -<p>Storage classes are often packaged with CSI drivers. Each StorageClass contains the fields “provisioner”, “parameters”, and “reclaimPolicy”. The provisioner field is used to determine what CSI driver is used for provisioning volumes.</p> -<p>This is an example of the storage class packaged with the AzureFiles CSI driver:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">StorageClass</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">storage.k8s.io/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azurefileshare</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">provisioner</span>: <span style="color:#ae81ff">file.csi.azure.com</span> <span style="color:#75715e"># replace with &#34;kubernetes.io/azure-file&#34; if aks version is less than 1.21</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">mountOptions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">dir_mode=0777</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">file_mode=0777</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">uid=0</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">gid=0</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">mfsymlinks</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">cache=strict</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">actimeo=30</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">parameters</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">skuName</span>: <span style="color:#ae81ff">Standard_LRS</span> -</span></span></code></pre></div><p>You can see in the above manifest that the provisioner is set to ‘file.csi.azure.com.’ When a pod uses a PVC in its manifest that references this storage class, the provisioner will dynamically manage the underlying storage.</p> -<p>The name of the storageClass is referenced in the persistentVolumeClaim:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">8Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">azurefileshare</span> -</span></span></code></pre></div><p>You could then reference this PVC in a pod:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/mnt/share</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span></code></pre></div><p>That concludes this article. I know that is a lot of information! As always, if you have any questions or comments, please reach out.</p> - - - + http://localhost:1313/posts/2022-03-01-kubernetes-storage-simplified/ + In this blog post, we will attempt to explain the current storage options that exist in Kubernetes. If you are new to Kubernetes, learning about its capabilities of managing the application state can be a daunting task. Container images are built-in layers, with the runtime layer being writable. However, any files on this writable layer are only available for the container’s lifetime. We can mount a volume to a directory inside the container to have persistent data. + Accessing Secrets Securely in Azure DevOps Pipelines - https://rnemeth90.github.io/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ + http://localhost:1313/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ Sat, 19 Feb 2022 16:02:50 +0000 - - https://rnemeth90.github.io/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ - <p>This post will cover a secure method for accessing secrets in Azure DevOps pipelines.</p> -<h2 id="why-azure-key-vault" >Why Azure Key Vault? -<span> - <a href="#why-azure-key-vault"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Azure Key Vault is an Azure cloud service used to securely store secrets, keys, and certificates. A secret can be any string of characters, such as API keys, passwords, URLs, etc. Azure Key Vault encrypts data at rest and in transit using HTTPS. Depending on the type of Key Vault you are using, data at rest is encrypted using software encryption (AES 256) or HSM-backed keys.</p> -<p>Azure Key Vault also gives us the ability to control access to secrets, keys, and certificates using native Key Vault access policies or the newer option of Azure IAM (RBAC) integration.</p> -<h2 id="what-are-variable-groups" >What are Variable Groups? -<span> - <a href="#what-are-variable-groups"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>It’s all in the name. Variable groups are simply a method of grouping Azure DevOps pipeline variables. If you created a release for an application named MyAwesomeApp, you could create a variable group named myawesomeapp-var-group that could then store all of the variables you reference in the release. It’s simply a method of organizing variables.</p> -<p>You apply permissions to variable groups so that only certain people and pipelines/releases are able to use them.</p> -<p>You can read more here about variable groups and their usage:</p> -<p><a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/library/variable-groups?view=azure-devops&amp;tabs=yaml#use-a-variable-group">https://docs.microsoft.com/en-us/azure/devops/pipelines/library/variable-groups?view=azure-devops&amp;tabs=yaml#use-a-variable-group</a></p> -<h2 id="creating-a-key-vault-and-adding-secrets" >Creating a Key Vault and Adding Secrets -<span> - <a href="#creating-a-key-vault-and-adding-secrets"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p><strong>If you already have a Key Vault, skip this section.</strong></p> -<p>In this post, we will create a Key Vault using the AzureCLI. To create the Vault and a secret, run these commands:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># Create a resource group</span> -</span></span><span style="display:flex;"><span>az group create --location &lt;location&gt; --name &lt;resource-group-name&gt; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Create a KeyVault</span> -</span></span><span style="display:flex;"><span>az keyvault create --name &lt;keyvault-name&gt; --resource-group &lt;resource-group-name&gt; --enable-soft-delete -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Create some secrets in the Key Vault</span> -</span></span><span style="display:flex;"><span>az keyvault secret set --name username --vault-name &lt;keyvault-name&gt; --value &lt;username&gt; -</span></span><span style="display:flex;"><span>az keyvault secret set --name password --vault-name &lt;keyvault-name&gt; --value &lt;password&gt; -</span></span><span style="display:flex;"><span>az keyvault secret set --name tenantId--vault-name &lt;keyvault-name&gt; --value &lt;tenant id&gt; -</span></span></code></pre></div><p>You will need to update the location and resource group name with whatever values you want. You will also need to update the username, password, and your Azure AD tenant ID. The username you choose will need read access to your subscription.</p> -<h2 id="creating-a-variable-group" >Creating a Variable Group -<span> - <a href="#creating-a-variable-group"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Now we’ll create the variable group in Azure DevOps.</p> -<p>Go to your Azure DevOps project &gt; Pipelines &gt; Library and click “+ Variable Group”:</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image.png"></a></p> -<p>Give your variable group a name. Then toggle the switch “Link secrets from an Azure key vault as variables”. Select your Azure Subscription (you may need to authorize DevOps access to the subscription, and then select the Key Vault.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-1.png"></a></p> -<p>Now we can add the secrets from the Key Vault to the variable group. Under “Variables”, click the “+ Add” button. Select the checkbox next to any secrets you want to add to the variable group, and then click “Ok”.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-7.png"></a></p> -<p>Finally, click the “Save” button. You now have a variable group with secrets linked to a Key Vault. Notice the name of the secret is the only thing visible from the variable group. If you were to update the secret value in the Key Vault, Azure DevOps would automatically pick up the new value.</p> -<h2 id="use-the-variable-group-in-a-pipeline" >Use the Variable Group in a Pipeline -<span> - <a href="#use-the-variable-group-in-a-pipeline"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Now that we have our variable group in place, let’s use it in a pipeline. In Azure DevOps, go to Pipelines and click “New pipeline”.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-8-1024x596.png"></a></p> -<p>Choose “Azure Repos Git” &gt; “&lt; your git repo&gt; “, “Starter Pipeline”, and then paste in the following code (You will need to update the ‘azureSubscription’ field with your SPN):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">variables</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">group</span>: <span style="color:#ae81ff">kv-secrets</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pr</span>: <span style="color:#ae81ff">none</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">stages</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">stage</span>: <span style="color:#ae81ff">print_resource_groups</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">jobs</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">job</span>: <span style="color:#ae81ff">print_resource_groups</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">continueOnError</span>: <span style="color:#66d9ef">false</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">task</span>: <span style="color:#ae81ff">AzureCLI@2</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">inputs</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">azureSubscription</span>: <span style="color:#e6db74">&#39;&lt;Your SPN&gt;&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">scriptType</span>: <span style="color:#e6db74">&#39;bash&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">scriptLocation</span>: <span style="color:#e6db74">&#39;inlineScript&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">inlineScript</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az login --service-principal --username $(username) --password $(password) --tenant $(tenantId) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az group list</span> -</span></span></code></pre></div><p>Now click “Save and Run”, and then “Save and Run” again.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-9-1024x596.png"></a></p> -<p>Once the pipeline finishes running, you can see that it was able to read the subscription and create a list of all resource groups found.</p> -<p>This is a simple example of using Key Vault credentials in a pipeline. But you can imagine how useful this could be in more complex scenarios.</p> -<p>That’s all for now. If you have any questions, feel free to reach out!</p> - - - + http://localhost:1313/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ + This post will cover a secure method for accessing secrets in Azure DevOps pipelines. Why Azure Key Vault? Link to heading Azure Key Vault is an Azure cloud service used to securely store secrets, keys, and certificates. A secret can be any string of characters, such as API keys, passwords, URLs, etc. Azure Key Vault encrypts data at rest and in transit using HTTPS. Depending on the type of Key Vault you are using, data at rest is encrypted using software encryption (AES 256) or HSM-backed keys. + Kubernetes Pod Eviction - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ Sat, 05 Feb 2022 23:49:16 +0000 - - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ - <p>In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation.</p> -<h2 id="what-is-pod-eviction" >What is Pod Eviction? -<span> - <a href="#what-is-pod-eviction"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. The most common of which is resource starvation on a node. This is referred to as “node-pressure eviction.”</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>NAME READY STATUS RESTARTS AGE -</span></span><span style="display:flex;"><span>nginx 0/1 Evicted <span style="color:#ae81ff">0</span> 10s -</span></span></code></pre></div><h2 id="eviction-process" >Eviction Process -<span> - <a href="#eviction-process"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The kubelet process running on the node monitors resources such as CPU, memory, disk space, inodes, etc. When one of these resources reaches a certain consumption level, the kubelet will first attempt to clean up resources by deleting non-running pods and images (in the case of storage starvation). The kubelet will then fail one or more pods on the node to reclaim resources. The class of the pod determines the order in which it does this.</p> -<p><strong>Pod Classes</strong></p> -<ul> -<li>Guaranteed: Pods that have requests and limits configured for both CPU and memory</li> -<li>Burstable: Pods with a resource request configured for memory or CPU</li> -<li>Best Effort: Pods without any requests or limits</li> -</ul> -<p>The kubelet will first evict any “best-effort” pods. If this is not enough, the kubelet will evict any “burstable” pods. Pods within the “guaranteed” class are theoretically safe from eviction.</p> -<p>During a node-pressure eviction, the kubelet sets the PodPhase for the selected pods to “Failed.” This causes the pods to terminate. If a daemonSet or replicaSet manages the pod, the Kubernetes controller-manager will create new pods on another node.</p> -<h2 id="recovery" >Recovery -<span> - <a href="#recovery"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Node-pressure eviction is almost always avoidable. We can prevent this type of issue by ensuring that we properly size our clusters and create resource limits for pods.</p> -<p><strong>Resource</strong> <strong>Requests and Limits:</strong></p> -<ul> -<li>Requests: The minimum amount of resources (CPU/memory) that a container needs to start.</li> -<li>Limits: The maximum amount of resources that a container is allowed to use.</li> -</ul> -<p>Pod resources and requests can be defined in a pod spec or deployment spec. Below is an example of a pod spec with resource requests and limits defined:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">frontend</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">nginx</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;64Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;250m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">limits</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;128Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;500m&#34;</span> -</span></span></code></pre></div><p>You will often need to clean up evicted pods manually. If you find that your cluster has a large amount of evicted pods, you can clean them up with the following kubectl commands:</p> -<p><strong>To see all failed pods in the cluster:</strong></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl get pod --all-namespaces --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Failed -</span></span></code></pre></div><p><strong>To remove all failed pods in the cluster:</strong></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl delete pod --all-namespaces --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Failed -</span></span></code></pre></div><p>I hope this article has been helpful. Please reach out if you have any questions or comments! Also, if you would like to learn more, take a look at the official Kubernetes docs:</p> -<p><a href="https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/">https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/</a></p> - - - + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ + In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation. What is Pod Eviction? Link to heading Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. + Azure Kubernetes sFTP Solution - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ + http://localhost:1313/posts/2022-01-16-azure-kubernetes-sftp-solution/ Sun, 16 Jan 2022 07:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ - <p>In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault.</p> -<p>Here is the link to my Github account where you can download the code mentioned in this article:</p> -<p><a href="https://github.com/rnemeth90/kubernetes-sftp">https://github.com/rnemeth90/kubernetes-sftp</a></p> -<p>We will work through the following steps in this article:</p> -<ol> -<li>Deploy the AzureFile CSI driver to the AKS cluster</li> -<li>Create a configMap that our initContainer will</li> -<li>Deploy a persistent volume claim that an Azure File share will back</li> -<li>Deploy a replicaSet consisting of our initContainer and application container</li> -<li>Deploy a service to serve traffic</li> -</ol> -<p>First, you will need to deploy the Azure Files CSI driver to your AKS cluster. AKS uses this daemon set to dynamically provision/destroy Azure NFSv4 File Shares. The Azure Files CSI driver creates a storage account in the node pool resource group, in which it will then provision the file share.</p> -<p>Deploying the Azure Files CSI driver is a simple task. You will need to run this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/install-driver.sh | bash -s master -- -</span></span></code></pre></div><p>You can use the following commands to verify that the daemon set has exists:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl -n kube-system get pod -o wide --watch -l app<span style="color:#f92672">=</span>csi-azurefile-controller -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>kubectl -n kube-system get pod -o wide --watch -l app<span style="color:#f92672">=</span>csi-azurefile-node -</span></span></code></pre></div><figure class="wp-block-coblocks-gallery-masonry masonry-grid has-border-radius-10 has-medium-gutter"><figure class="wp-block-image size-large masonry-brick">[![Image gallery image](https://rnemeth90.github.io/wp-content/uploads/2022/01/image-1-1024x434.png)](https://rnemeth90.github.io/wp-content/uploads/2022/01/image-1.png)</figure></figure>Next, you need to create a storage class by deploying this yaml file: -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl create -f https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/example/storageclass-azurefile-nfs.yaml -</span></span></code></pre></div><p>Read more about the AzureFiles CSI driver at the following Github link:</p> -<p><a href="https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/install-driver-on-aks.md">https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/install-driver-on-aks.md</a></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ConfigMap</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">creationTimestamp</span>: <span style="color:#66d9ef">null</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">testcm</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">init.sh</span>: |-<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> #!/bin/bash -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> CONF_FILE=&#34;/etc/sftp/users.conf&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> KEYVAULT=&#34;Insert name of Key Vault&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_ID=&#34;Insert service principal Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_PASSWORD=&#34;Insert service principal password&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_TENANT_ID=&#34;Insert Az AAD Tenant Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SUBSCRIPTION_ID=&#34;Insert Az Subscription Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az login --service-principal --username &#34;${AZ_SPN_ID}&#34; --password &#34;${AZ_SPN_PASSWORD}&#34; --tenant &#34;${AZ_SPN_TENANT_ID}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az account set --subscription &#34;${AZ_SUBSCRIPTION_ID}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETS+=($(az keyvault secret list --vault-name $KEYVAULT --query &#34;[].id&#34; -o tsv)) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> chmod 755 /home -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [[ -e $CONF_FILE ]]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> rm -rf &#34;${CONF_FILE}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> touch $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> else -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> touch $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> for SECRET in &#34;${SECRETS[@]}&#34;; do -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETNAME=$(basename $SECRET | tr -d &#39;\r&#39;) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETVALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $SECRETNAME --query &#39;value&#39; | tr -d &#39;&#34;&#39; | tr -d &#39;\r&#39;) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;$SECRETNAME:$SECRETVALUE:::upload&#34; &gt;&gt; $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> done -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [[ ! -s $CONF_FILE ]]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;** ERROR: user.conf is empty&#34; 1&gt;&amp;2 -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> exit 1 -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi</span> -</span></span></code></pre></div><p>The initContainer will use this configMap to read secrets from an Azure Key Vault and then write the secrets to the users.conf file. The users.conf file contains user account information. In the Key Vault, the secret name should be the username and the secret value should be the password. This Key Vault must exist and contain the secrets prior to deploying this solution.</p> -<p>When I deployed this solution in my environment, I used an Azure DevOps pipeline to create/manage the Key Vault with Terraform and then deploy the secrets using an inline Powershell script. However, this is beyond the scope of this article, and I will not be covering it here. You will also need to create a Service Principal in your AAD tenant and grant it access to the Key Vault. The Service Principal needs to have at least read access to the Key Vault.</p> -<p>Before deploying the configMap, you need to fill in values for these variables:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span> KEYVAULT<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert name of Key Vault&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert service principal Id&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_PASSWORD<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert service principal password&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_TENANT_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert Az AAD Tenant Id&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SUBSCRIPTION_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert Az Subscription Id&#34;</span> -</span></span></code></pre></div><p>These values pertain to the service principal with read access to the Key Vault. After filling out these variables, you can deploy the configMap using kubectl.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl create -f configmap.yaml -</span></span></code></pre></div><p>You can deploy the PVC using this yaml file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">azurefile-csi-nfs</span> -</span></span></code></pre></div><p>When creating the persistent volume claim for the deployment, you specify azurefile-csi-nfs as the StorageClass. This will create an NFSv4 share in a premium storage account. The reclaim policy of the storage class ensures that the file share is deleted when the associated Persistent Volume is deleted. Change the reclaim policy to “Retain” if you want the file shares to persist after deleting the PV. Furthermore, the storage class enables the file share to be expandable by modifying the storage request size on the PVC.</p> -<p>After deploying the PVC, you can verify its existence by running:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl get pvc -</span></span></code></pre></div><p>You should see output similar to the following (the manifest for the replicaSet is by far the most complicated of all the code referenced here):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Deployment</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">matchLabels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">strategy</span>: {} -</span></span><span style="display:flex;"><span> <span style="color:#f92672">template</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initContainer</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">chmodder</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">mcr.microsoft.com/azure-cli</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">command</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">/bin/sh</span> -</span></span><span style="display:flex;"><span> - -<span style="color:#ae81ff">c</span> -</span></span><span style="display:flex;"><span> - <span style="color:#e6db74">&#34;/scripts/init.sh&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/scripts</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">docker.io/atmoz/sftp:alpine</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">imagePullPolicy</span>: <span style="color:#ae81ff">IfNotPresent</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;64Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;250m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">limits</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;128Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;500m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">livenessProbe</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tcpSocket</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initialDelaySeconds</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">timeoutSeconds</span>: <span style="color:#ae81ff">5</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">periodSeconds</span>: <span style="color:#ae81ff">10</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">failureThreshold</span>: <span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readinessProbe</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tcpSocket</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initialDelaySeconds</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">timeoutSeconds</span>: <span style="color:#ae81ff">5</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">periodSeconds</span>: <span style="color:#ae81ff">10</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">failureThreshold</span>: <span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/home</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/etc/sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">dnsPolicy</span>: <span style="color:#ae81ff">ClusterFirst</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">restartPolicy</span>: <span style="color:#ae81ff">Never</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">configMap</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">emptyDir</span>: {} -</span></span></code></pre></div><p>You may need to change the CPU/memory requests and limits. These values worked for me, but your results may vary. You can also add/change the labels as you see fit.</p> -<p>This will handle routing traffic to our pods.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Service</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp-service</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">LoadBalancer</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">ports</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">protocol</span>: <span style="color:#ae81ff">TCP</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">targetPort</span>: <span style="color:#ae81ff">22</span> -</span></span></code></pre></div><p>Users will be connected in a round-robin fashion to the pods. This manifest will create a service of type LoadBalancer. Which will in turn create a new public Azure Load Balancer in the resource group that contains your Azure Kubernetes Service cluster if one does not already exist. If you already have a public load balancer, a new frontend IP address will be added.</p> -<p>That’s all for now. Please feel free to contact me if you have any questions.</p> - - - + http://localhost:1313/posts/2022-01-16-azure-kubernetes-sftp-solution/ + In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault. Here is the link to my Github account where you can download the code mentioned in this article: https://github.com/rnemeth90/kubernetes-sftp We will work through the following steps in this article: + WSUS: Update Files Not Downloading - https://rnemeth90.github.io/posts/2022-01-14-wsus-update-files-not-downloading/ + http://localhost:1313/posts/2022-01-14-wsus-update-files-not-downloading/ Fri, 14 Jan 2022 22:01:40 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-wsus-update-files-not-downloading/ - <p>This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-18_10h02_21.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-18_10h02_21.png" alt=""></a></p> -<p>You may also see this event (or similar) in the Event Log.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_32.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_32.png" alt=""></a></p> -<p>This problem is caused by not specifying a valid path when assigning the WSUS content drive when first installing the role. The first time you load the WSUS console after installing the role, you will be prompted to specify the path to store Windows Update files. WSUS does not like to have its content directory be the root of a partition. For example, if I were to specify “e:” as the path for the Windows Update content, the wizard would give you an error message stating that the path is not valid. However, it doesn’t prompt you to re-enter the path if you click close. The WSUS console opens immediately after and that invalid path is where WSUS will try to store your update files. This is and has been a known bug for a while and needs to be addressed by Microsoft. Evidence of the invalid path can be found in the registry under:</p> -<p>HKLM\Software\Microsoft\UpdateServices\Server\SetupContentDir</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_44.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_44.png" alt=""></a></p> -<p>If you come across this problem, you can change the ContentDir above to a valid path. Keep in mind that it cannot be the root of a partition. You need to specify a drive letter with a subfolder (eg: e:wsus).</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h54_54.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h54_54.png" alt=""></a></p> -<p>The other option is to reinstall the WSUS role. If you remove the role, the WID database is not removed, unless you remove that role as well (or manually delete the database). This means that when you reinstall the WSUS role, it will be able to use that same database and any clients that have contacted the WSUS server will immediately show up in the console. The same is true for update metadata. The new WSUS installation will still have the same approvals, denials, etc. as the old installation.</p> -<p>Regardless of what option you choose, I suggest rebooting the server after you make the changes.</p> - - - + http://localhost:1313/posts/2022-01-14-wsus-update-files-not-downloading/ + This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates: You may also see this event (or similar) in the Event Log. This problem is caused by not specifying a valid path when assigning the WSUS content drive when first installing the role. The first time you load the WSUS console after installing the role, you will be prompted to specify the path to store Windows Update files. + Active Directory Migration Toolkit The RPC Server is Unavailable - https://rnemeth90.github.io/posts/2022-01-14-active-directory-migration-toolkit-the-rpc-server-is-unavailable/ + http://localhost:1313/posts/2022-01-14-active-directory-migration-toolkit-the-rpc-server-is-unavailable/ Fri, 14 Jan 2022 21:55:56 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-active-directory-migration-toolkit-the-rpc-server-is-unavailable/ - <p>When migrating computer objects using the Active Directory Migration Tool, you may encounter the following error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_09.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_09.png" alt=""></a></p> -<p>In addition, the Migration Log may show the following error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_20.png" alt=""></a></p> -<p>This is typically caused by a host-side firewall. To resolve this, deploy a GPO to disable the Windows firewall prior to migrating the computer account. I like to create a special OU for computers (I typically name it “PreMigration”) that I will move computer objects to prior to migrating them. This OU will have two policies applied. One to disable the Windows Firewall and another to start the Remote Registry service. Both are required for the computer object to successfully migrate.</p> - + http://localhost:1313/posts/2022-01-14-active-directory-migration-toolkit-the-rpc-server-is-unavailable/ + When migrating computer objects using the Active Directory Migration Tool, you may encounter the following error: In addition, the Migration Log may show the following error: This is typically caused by a host-side firewall. To resolve this, deploy a GPO to disable the Windows firewall prior to migrating the computer account. I like to create a special OU for computers (I typically name it “PreMigration”) that I will move computer objects to prior to migrating them. - Continuous Deployment Models - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ + http://localhost:1313/posts/2022-01-14-continuous-deployment-models/ Fri, 14 Jan 2022 19:24:01 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ - <p>When deploying new software releases to servers or (insert -as-a-service&gt; here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments.</p> -<h2 id="bluegreen-deployments" >Blue/Green Deployments -<span> - <a href="#bluegreen-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. Instead, it gets deployed to another set of servers (blue) first. Since the blue servers are not currently serving any traffic for users, the deployment has no impact. However, once the deployment has been completed successfully and tested, users will be directed to the new deployment (blue). You can control all user traffic or a subset of user traffic if your load balancer supports it (referred to as ‘Progressive Exposure’).</p> -<p>The next release will then repeat the same process. Blue would be the current production environment, so you would first deploy to the green servers. This model requires two sets of identical hosts and a load balancer or reverse proxy in front of them. If there are any unexpected issues with the new release, it is straightforward to switch back to the previous release. The disadvantage to this type of model is that it requires having redundant environments (and potentially wasted resources). However, this is less of a concern if using container orchestration platforms such as Kubernetes.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/01/2022-01-19_07h57_58-1024x575.png" alt="Blue Green deployment model"></p> -<h2 id="immutable-servers" >Immutable Servers -<span> - <a href="#immutable-servers"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>There is an alternative method of blue/green deployments called “immutable servers”. This method is identical to blue/green deployments as described above. However, after switching user traffic over to the servers with the new release, the old servers are destroyed. They are not used again. This type of model becomes particularly efficient when using a pipeline that is capable of creating servers for you (i.e., Azure DevOps Pipelines)</p> -<h2 id="canary-deployments" >Canary Deployments -<span> - <a href="#canary-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>In a canary deployment, not all users are routed to the new release immediately. Only a limited percentage of users get access to the new release. These users are the canaries. They should be monitored closely, so it is important to be using Not all users are routed to the new release immediately in a canary deployment. Only a limited percentage of users get access to the latest release. These users are the canaries.</p> -<p>Organizations should monitor the canaries closely, so it is essential to be using monitoring software capable of looking at the statistics of a web application from the users’ perspective (for example, Application Insights). The number of canaries can increase until all traffic is directed to the new release over time. The most significant advantage of this method is limited exposure to issues. If a problem appears after the release is deployed, only a small subset of users will experience it. After you fix the issues and redeploy the release, it’s best to select a different group of users to be canaries.</p> -<h2 id="ring-based-deployments" >Ring Based Deployments -<span> - <a href="#ring-based-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>A ring-based deployment has multiple production environments. Each serves a limited number of users, similar to a canary deployment. However, you can have as many production environments as you want with a ring-based deployment. New releases are deployed to the rings one by one over time.</p> -<h2 id="feature-flag-deployments" >Feature Flag Deployments -<span> - <a href="#feature-flag-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Feature flags are used to expose new features to sets of users slowly. Unlike the other deployment models, they are not implemented in the infrastructure. Instead, they are typically implemented and enabled in code or database. An example would be a feature flag in a database that gives users access to a button on your web page. A developer could enable the flag for a set of users. These users would be able to see the button; other users would not. Feature flags can even toggle bug fixes or performance improvements.</p> -<p>I will cover implementing blue/green deployments in Azure using Azure DevOps and App Services in a future article.</p> - - - + http://localhost:1313/posts/2022-01-14-continuous-deployment-models/ + When deploying new software releases to servers or (insert -as-a-service&gt; here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments. Blue/Green Deployments Link to heading Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. + Deploy Azure VMs Using Azure Devops CI/CD Pipeline - https://rnemeth90.github.io/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ + http://localhost:1313/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ Fri, 14 Jan 2022 18:46:35 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ - <p>This article assumes that you have already created a pipeline in Azure Devops and have it linked to an Azure Devops repo. You will need to create a variable named $vmpassword and assign it the value stored in your key vault.</p> -<p>To create a release pipeline that will automatically create a VM (using the password stored in key vault for the local administrator account), do the following:</p> -<ol> -<li>Create a new release pipeline</li> -</ol> -<p><img src="https://www.rnemeth90.github.io/content/images/2021/01/image-13.png" alt=""></p> -<p>3. In the “select a template” box, choose “Empty Job”<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-14.png" alt=""></p> -<p>4. Select “Tasks” in the navigation bar, and then select the appropriate stage. For simplicities sake, we will be using 1 stage within this release.<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-15.png" alt=""></p> -<p>5. Click on the “+” in the Agent job bar, and then in the “Add tasks” section, type in “Key Vault”. Click “Azure Key Vault” and then click “Add”. <img src="https://www.rnemeth90.github.io/content/images/2021/01/image-16.png" alt=""></p> -<p>6. Click on the “Azure Key Vault:” task to configure it. Select your subscription, Key Vault, and the secrets filter. You can also create the $vmpassword variable as a variable within your devops project, rather than assigning it as a secret filter for the release. <img src="https://www.rnemeth90.github.io/content/images/2021/01/image-20.png" alt=""></p> -<p>7. In your Key Vault, you need to grant the devops account access to the Key Vault. To do this, go to your Key Vault and create a new access policy. This policy will be assigned to a service principal that is being used by your Azure Devops project. To find the ID of this service principal, go to your project settings, and under “Pipelines”, click on “Service Connections”. Then select the service connection that resembles your subscription. After doing this, click “Manage Service Principal”. In the service principal window, click “Manifest” and then find the “name” tag within the JSON.<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-19.png" alt=""></p> -<p>8. Now go back to your key vault, and assign an access policy for this service principal. Grant the principal read and list for secrets.</p> -<p>9. Add another agent job for the task (see step 6) and search for “azure cli”. Click on “Add” for Azure CLI. Configure the settings for this job as below:<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-18.png" alt=""></p> -<p>10. Save and run your pipeline. Give it some time to complete, and go take a look at your newly created VM. This is just a very simple example of creating a server as part of a CI/CD pipeline. You can then deploy your code to it, run some tests, destroy them VM, etc. Completely automated.<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-21.png" alt=""></p> - - - + http://localhost:1313/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ + This article assumes that you have already created a pipeline in Azure Devops and have it linked to an Azure Devops repo. You will need to create a variable named $vmpassword and assign it the value stored in your key vault. To create a release pipeline that will automatically create a VM (using the password stored in key vault for the local administrator account), do the following: Create a new release pipeline 3. + Azure Devops &#8211; Self Hosted Agent Service Won&#8217;t Start &#8211; Incorrect Function - https://rnemeth90.github.io/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ + http://localhost:1313/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ Fri, 14 Jan 2022 18:45:00 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ - <p>I setup a self hosted agent for Azure Devops this morning on Server 2012 R2 (legacy Visual Studio dependencies…) and found that I was unable to start the service. The error I received was “Error 1 Incorrect Function” when attempting to start the service in services.msc.</p> -<p>I was attempting to run the agent from within my user profile downloads folder. I originally was not aware the service would be running from this directory. I thought it would copy its binary files to program files directory or programdata, like 99% of all other apps. The service installs and attempts to run itself as the “network service” authority. This account does not have permission to a user profile folder by default, and the installation script is not able to grant it permission for some reason (I didn’t investigate this further). I removed the agent, moved the installation files to the root of c:, and then reinstalled. The agent service is now able to start successfully.</p> - + http://localhost:1313/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ + I setup a self hosted agent for Azure Devops this morning on Server 2012 R2 (legacy Visual Studio dependencies…) and found that I was unable to start the service. The error I received was “Error 1 Incorrect Function” when attempting to start the service in services.msc. I was attempting to run the agent from within my user profile downloads folder. I originally was not aware the service would be running from this directory. - Azure Tenant Maintenance &#8211; Purge Empty Resource Groups - https://rnemeth90.github.io/posts/2022-01-14-azure-tenant-maintenance-purge-empty-resource-groups/ + http://localhost:1313/posts/2022-01-14-azure-tenant-maintenance-purge-empty-resource-groups/ Fri, 14 Jan 2022 18:43:35 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-azure-tenant-maintenance-purge-empty-resource-groups/ - <p>This will be the first article in a series about maintaining Azure tenants and subscriptions.</p> -<p>If you currently, or have ever, worked in a large Azure environment, you know how easily resource creep can occur. Resource Groups, VM disks and network interfaces, network security groups, etc. can easily fall out of sight and be forgotten about. This isn’t a big concern for resources that are free of cost, like resource groups. However, if you delete several virtual machines, the disks that were attached to those virtual machines linger, and you continue to pay the cost of storing them.</p> -<p>In this blog post, we will review a script I created for removing empty resource groups. We will then add this script to an Azure Automation Account and link it to a schedule. We will assume you already have an Azure Automation Account in existence, and the Automation Account has a credential object named ‘AzureRunAsConnection’.</p> -<p>To get started, you can download the script here:</p> -<p><a href="https://github.com/rnemeth90/azure-automation/blob/master/clean-empty-resource-groups.ps1">https://github.com/rnemeth90/azure-automation/blob/master/clean-empty-resource-groups.ps1</a></p> -<p>This particular runbook will require that the “AZ.Resources” module be loaded in the Automation Account. To import this module, go to your automation account and then click on “Modules” under “Shared Resources”. Then, click on “Browse Gallery”.</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image.png"></a></p> -<p>In the search bar, type in “Az.resources”, then click on the module and click “Import”. If you see a message like this, you will need to add any modules that az.resources depends on before importing it.</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image-1.png"></a></p> -<p>You can go back and add those modules using the same process, and then attempt to import the “Az.resources” module again. Importing these modules may take several minutes. In my experience, it takes around 10-15 minutes.</p> -<p>Once these modules are imported you can import the PowerShell runbook you downloaded earlier from Github. To do that, browse to the Runbooks section of your Automation Account and then click “Import a Runbook”:</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image-2.png"></a></p> -<p>In the context menu that appears, browse to the runbook and upload it, choose “PowerShell” as the runbook type, and then click Create:</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image-3.png"></a></p> -<p>In the Editor Pane, click on “Test Pane”. This will bring you to the Test Pane for the runbook. This will allow you to test the runbook before running it in your environment. Click “Start” in the Test Pane. This particular runbook will output to screen any changes it will make, so you can see the results here.</p> -<p>As you can see here, the runbook did find some empty resource groups, but did not remove them:</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image-4.png"></a></p> -<p>This is because we have a variable in the runbook that controls whether or not any write/update actions will be taken on resources. Click the X in the upper right corner to go back to the editor, and change the value in the screenshot below from “0” to “1”.</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image-8.png"></a></p> -<p>If you’d like, you can test the runbook again, or you can click “Publish” to publish it to your Automation Account. Once it’s published, you can link it to a schedule so that it runs automatically.</p> -<p>Click “Publish”:</p> -<p>&lt;<a href="https://www.rnemeth90.github.io/content/images/2021/06/image-9.png"></a></p> -<p>Then, on the Runbook page, click “Schedules”, and then “Add a schedule”:</p> -<p><a href="https://www.rnemeth90.github.io/content/images/2021/06/image-10.png"></a></p> -<p>Fill out the wizard that pops up to create a schedule and link it to your workbook. This concludes this article.</p> -<p>In the next post, we will take a look at removing empty resource groups automatically. Stay tuned.</p> - - - + http://localhost:1313/posts/2022-01-14-azure-tenant-maintenance-purge-empty-resource-groups/ + This will be the first article in a series about maintaining Azure tenants and subscriptions. If you currently, or have ever, worked in a large Azure environment, you know how easily resource creep can occur. Resource Groups, VM disks and network interfaces, network security groups, etc. can easily fall out of sight and be forgotten about. This isn’t a big concern for resources that are free of cost, like resource groups. + Exam AZ-303: Microsoft Azure Architect Technologies Study Guide - https://rnemeth90.github.io/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ + http://localhost:1313/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ Wed, 16 Dec 2020 14:44:00 +0000 - - https://rnemeth90.github.io/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ - <p><span style="font-family: arial;">I recently passed the AZ-303 exam. Below are some of the resources I used to prepare for the exam. In addition to the links below, I also used Alan Rodrigues’ course on Udemy. </span></p> -<p><span style="font-family: arial;"><a href="https://www.udemy.com/course/az-102-azure-administrator-certification-transition/">https://www.udemy.com/course/az-102-azure-administrator-certification-transition/</a> -</span></p> -<p><span style="font-family: arial;">The Udemy course and Microsoft Docs are enough to pass the exam. The course has some good practice exams and labs that align well with what you’ll see on the real exam regarding difficulty. I was scoring in the high 90’s on the Udemy exams. On the real exam, my score was 923. So, I think, if you comprehend the material well, and get high scores on Udemy practice exams, you’ll do well on the real exam.</span></p> -<p><span style="font-family: arial;">Just wanted to share my experience, hopefully it helps.</span></p> -<p><strong><u><span style="font-size: large;">Implement and Monitor an Azure Infrastructure (50-55%)</span></u></strong></p> -<p><span style="font-size: medium;"><strong>Implement cloud infrastructure monitoring</strong></span></p> -<ul> -<li> -<p>monitor security</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/security-center/security-center-introduction">What is Azure Security Center?</a></p> -</li> -<li> -<p>monitor performance</p> -</li> -<li> -<p>configure diagnostic settings on resources</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/diagnostic-settings">Create diagnostic settings to send platform logs and metrics to different destinations</a></p> -</li> -<li> -<p>create a performance baseline for resources</p> -</li> -<li> -<p><a href="https://cloudacademy.com/course/analyzing-resource-utilization-azure/resource-baseline/">Analyzing Resource Utilization on Azure</a></p> -</li> -<li> -<p>monitor for unused resources</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cost-management-billing/costs/quick-acm-cost-analysis?tabs=azure-portal">Quickstart: Explore and analyze costs with cost analysis</a></p> -</li> -<li> -<p>monitor performance capacity</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/insights/vminsights-performance">How to chart performance with Azure Monitor for VMs</a></p> -</li> -<li> -<p>visualize diagnostics data using Azure Monitor</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/workbooks-overview">Azure Monitor Workbooks</a></p> -</li> -<li> -<p>monitor health and availability</p> -</li> -<li> -<p>monitor networking</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/insights/network-insights-overview">Azure Monitor for Networks</a></p> -</li> -<li> -<p>monitor service health</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/service-health/service-health-overview">Service Health overview</a></p> -</li> -<li> -<p>monitor cost</p> -</li> -<li> -<p>monitor spend</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cost-management-billing/costs/quick-acm-cost-analysis?tabs=azure-portal">Quickstart: Explore and analyze costs with cost analysis</a></p> -</li> -<li> -<p>report on spend</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cost-management-billing/understand/download-azure-invoice">View and download your Microsoft Azure invoice</a></p> -</li> -<li> -<p>configure advanced logging</p> -</li> -<li> -<p>implement and configure Azure Monitor insights, including App Insights, Networks, Containers</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/monitor-reference">What is monitored by Azure Monitor?</a></p> -</li> -<li> -<p>configure a Log Analytics workspace</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/learn/quick-create-workspace">Create a Log Analytics workspace in the Azure portal</a></p> -</li> -<li> -<p>configure logging for workloads</p> -</li> -<li> -<p>initiate automated responses by using Action Groups</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/action-groups">Create and manage action groups in the Azure portal</a></p> -</li> -<li> -<p>configure and manage advanced alerts</p> -</li> -<li> -<p>collect alerts and metrics across multiple subscriptions</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/alerts-metric">Create, view, and manage metric alerts using Azure Monitor</a></p> -</li> -<li> -<p>view Alerts in Azure Monitor logs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/alerts-activity-log">Create, view, and manage activity log alerts by using Azure Monitor</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement storage accounts</span></strong></p> -<ul> -<li> -<p>select storage account options based on a use case</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-account-create?tabs=azure-portal">Create a storage account</a></p> -</li> -<li> -<p>configure Azure Files and blob storage</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/files/storage-how-to-create-file-share?tabs=azure-portal">Create an Azure file share</a></p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-portal">Quickstart: Upload, download, and list blobs with the Azure portal</a></p> -</li> -<li> -<p>configure network access to the storage account</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-network-security">Configure Azure Storage firewalls and virtual networks</a></p> -</li> -<li> -<p>implement Shared Access Signatures and access policies</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-sas-overview">Grant limited access to Azure Storage resources using shared access signatures (SAS)</a></p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/rest/api/storageservices/define-stored-access-policy">Define a stored access policy</a></p> -</li> -<li> -<p>implement Azure AD authentication for storage</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-auth-aad">Authorize access to blobs and queues using Azure Active Directory</a></p> -</li> -<li> -<p>manage access keys</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-account-keys-manage?tabs=azure-portal">Manage storage account access keys</a></p> -</li> -<li> -<p>implement Azure storage replication</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/blobs/object-replication-configure?tabs=portal">Configure object replication for block blobs</a></p> -</li> -<li> -<p>implement Azure storage account failover</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-disaster-recovery-guidance">Disaster recovery and storage account failover</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement VMs for Windows and Linux</span></strong></p> -<ul> -<li> -<p>configure High Availability</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/manage-availability">Manage the availability of Linux virtual machines</a></p> -</li> -<li> -<p>configure storage for VMs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/managed-disks-overview">Introduction to Azure managed disks</a></p> -</li> -<li> -<p>select virtual machine size</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/sizes">Sizes for virtual machines in Azure</a></p> -</li> -<li> -<p>implement Azure Dedicated Hosts</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/dedicated-hosts-portal">Deploy VMs and scale sets to dedicated hosts using the portal</a></p> -</li> -<li> -<p>deploy and configure scale sets</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machine-scale-sets/quick-create-portal">Quickstart: Create a virtual machine scale set in the Azure portal</a></p> -</li> -<li> -<p>configure Azure Disk Encryption</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/windows/disk-encryption-overview">Azure Disk Encryption for Windows VMs</a></p> -</li> -</ul> -<p><span style="font-size: medium;"><strong>Automate deployment and configuration of resources</strong></span></p> -<ul> -<li> -<p>save a deployment as an Azure Resource Manager template</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/export-template-portal">Single and multi-resource export to a template in Azure portal</a></p> -</li> -<li> -<p>modify Azure Resource Manager template</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/overview">What are ARM templates?</a></p> -</li> -<li> -<p>evaluate location of new resources</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/view-activity-logs">View activity logs to monitor actions on resources</a></p> -</li> -<li> -<p>configure a virtual disk template</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/windows/capture-image-resource">Create a managed image of a generalized VM in Azure</a></p> -</li> -<li> -<p>deploy from a template</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/deploy-vms-from-vhd-templates/">Deploy Azure virtual machines from VHD templates</a></p> -</li> -<li> -<p>manage a template library</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/shared-image-galleries">Shared Image Galleries overview</a></p> -</li> -<li> -<p>create and execute an automation runbook</p> -</li> -<li> -<p><a href="https://azure.microsoft.com/en-us/blog/azure-automation-runbook-management/">Getting Started With Azure Automation – Runbook Management</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement virtual networking</span></strong></p> -<ul> -<li> -<p>implement VNet to VNet connections</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/vpn-gateway/vpn-gateway-howto-vnet-vnet-resource-manager-portal">Configure a VNet-to-VNet VPN gateway connection by using the Azure portal</a></p> -</li> -<li> -<p>implement VNet peering</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-peering-overview">Virtual network peering</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement Azure Active Directory</span></strong></p> -<ul> -<li> -<p>add custom domains</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/add-custom-domain">Add your custom domain name using the Azure Active Directory portal</a></p> -</li> -<li> -<p>configure Azure AD Identity Protection</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/identity-protection/overview-identity-protection">What is Identity Protection?</a></p> -</li> -<li> -<p>implement self-service password reset</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/tutorial-enable-sspr">Tutorial: Enable users to unlock their account or reset passwords using Azure Active Directory self-service password reset</a></p> -</li> -<li> -<p>implement Conditional Access including MFA</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/conditional-access/howto-conditional-access-policy-all-users-mfa">Conditional Access: Require MFA for all users</a></p> -</li> -<li> -<p>configure user accounts for MFA</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-userstates">Enable per-user Azure AD Multi-Factor Authentication to secure sign-in events</a></p> -</li> -<li> -<p>configure fraud alerts</p> -</li> -<li> -<p><a href="Enable%20per-user%20Azure%20AD%20Multi-Factor%20Authentication%20to%20secure%20sign-in%20events">Fraud alert</a></p> -</li> -<li> -<p>configure bypass options</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-server-settings#one-time-bypass">One-time bypass</a></p> -</li> -<li> -<p>configure Trusted IPs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-mfasettings#trusted-ips">Trusted IPs</a></p> -</li> -<li> -<p>configure verification methods</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/concept-sspr-howitworks#authentication-methods">Authentication methods</a></p> -</li> -<li> -<p>implement and manage guest accounts</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/external-identities/b2b-quickstart-add-guest-users-portal">Quickstart: Add guest users to your directory in the Azure portal</a></p> -</li> -<li> -<p>manage multiple directories</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/enterprise-users/licensing-directory-independence">Understand how multiple Azure Active Directory organizations interact</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement and manage hybrid identities</span></strong></p> -<ul> -<li> -<p>install and configure Azure AD Connect</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-install-express">Getting started with Azure AD Connect using express settings</a></p> -</li> -<li> -<p>identity synchronization options</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/plan-connect-user-signin">Azure AD Connect user sign-in options</a></p> -</li> -<li> -<p>configure and manage password sync and password writeback</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/tutorial-enable-sspr-writeback">Tutorial: Enable Azure Active Directory self-service password reset writeback to an on-premises environment</a></p> -</li> -<li> -<p>configure single sign-on</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-sso-quick-start">Azure Active Directory Seamless Single Sign-On: Quickstart</a></p> -</li> -<li> -<p>use Azure AD Connect Health</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/whatis-azure-ad-connect#what-is-azure-ad-connect-health">What is Azure AD Connect Health?</a></p> -</li> -</ul> -<p><strong><u><span style="font-size: large;">Implement Management and Security Solutions (25-30%)</span></u></strong></p> -<p><span style="font-size: medium;"><strong>Manage workloads in Azure</strong></span></p> -<ul> -<li> -<p>migrate workloads using Azure Migrate</p> -</li> -<li> -<p>assess infrastructure</p> -</li> -<li> -<p>select a migration method</p> -</li> -<li> -<p>prepare the on-premises for migration</p> -</li> -<li> -<p>recommend target infrastructure</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/migrate/tutorial-migrate-hyper-v">Migrate Hyper-V VMs to Azure</a></p> -</li> -<li> -<p>implement Azure Backup for VMs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/backup/backup-azure-vms-first-look-arm">Back up an Azure VM from the VM settings</a></p> -</li> -<li> -<p>implement disaster recovery</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/site-recovery/azure-to-azure-tutorial-enable-replication">Tutorial: Set up disaster recovery for Azure VMs</a></p> -</li> -<li> -<p>implement Azure Update Management</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/automation/update-management/enable-from-vm">Enable Update Management for an Azure VM</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement load balancing and network security</span></strong></p> -<ul> -<li> -<p>implement Azure Load Balancer</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/load-balancer/load-balancer-overview">What is Azure Load Balancer?</a></p> -</li> -<li> -<p>implement an application gateway</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/application-gateway/overview">What is Azure Application Gateway?</a></p> -</li> -<li> -<p>implement a Web Application Firewall</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/web-application-firewall/overview">What is Azure Web Application Firewall?</a></p> -</li> -<li> -<p>implement Azure Firewall</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/firewall/overview">What is Azure Firewall?</a></p> -</li> -<li> -<p>implement the Azure Front Door Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/frontdoor/quickstart-create-front-door">Quickstart: Create a Front Door for a highly available global web application</a></p> -</li> -<li> -<p>implement Azure Traffic Manager</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/traffic-manager/traffic-manager-overview">What is Traffic Manager?</a></p> -</li> -<li> -<p>implement Network Security Groups and Application Security Groups</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-network/network-security-groups-overview">Network security groups</a></p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-network/application-security-groups">Application security groups</a></p> -</li> -<li> -<p>implement Bastion</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/bastion/">Azure Bastion documentation</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement and manage Azure governance solutions</span></strong></p> -<ul> -<li> -<p>create and manage hierarchical structure that contains management groups</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/governance/management-groups/overview">What are Azure management groups?</a></p> -</li> -<li> -<p>subscriptions and resource groups</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-setup-guide/organize-resources?tabs=AzureManagementGroupsAndHierarchy">Organize your Azure resources effectively</a></p> -</li> -<li> -<p>assign RBAC roles</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal">Add or remove Azure role assignments using the Azure portal</a></p> -</li> -<li> -<p>create a custom RBAC role</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/custom-roles">Azure custom roles</a></p> -</li> -<li> -<p>configure access to Azure resources by assigning roles</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal">Add or remove Azure role assignments using the Azure portal</a></p> -</li> -<li> -<p>configure management access to Azure</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/manage-subscription-access-azure-rbac/">Manage access to an Azure subscription by using Azure role-based access control (RBAC)</a></p> -</li> -<li> -<p>interpret effective permissions</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/check-access">Quickstart: Check access for a user to Azure resources</a></p> -</li> -<li> -<p>set up and perform an access review</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/governance/access-reviews-overview">What are Azure AD access reviews?</a></p> -</li> -<li> -<p>implement and configure an Azure Policy</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/governance/policy/assign-policy-portal">Quickstart: Create a policy assignment to identify non-compliant resources</a></p> -</li> -<li> -<p>implement and configure an Azure Blueprint</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/governance/blueprints/overview">What is Azure Blueprints?</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Manage security for applications</span></strong></p> -<ul> -<li> -<p>implement and configure KeyVault</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/configure-and-manage-azure-key-vault/">Configure and manage secrets in Azure Key Vault</a></p> -</li> -<li> -<p>implement and configure Managed Identities</p> -</li> -<li> -<p><a href="https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=18fbca16-2224-45f6-85b0-f7bf2b39b3f3&amp;nonce=ef221978-b465-49a1-9226-e8a0e4d25480&amp;prompt=none&amp;redirect_uri=https%3A%2F%2Fdocs.microsoft.com%2F_themes%2Fdocs.theme%2Fmaster%2Fen-us%2F_themes%2Fglobal%2Fsign-in.html&amp;response_mode=fragment&amp;response_type=id_token&amp;scope=openid%20profile&amp;sso_reload=true&amp;state=silent%3A%2F%2Fhttps%3A%2F%2Fdocs.microsoft.com&amp;fromOrigin=https%3A%2F%2Fdocs.microsoft.com&amp;iframe-request-id=685d3411-99a9-4f94-81e4-d9b8af575600">What are managed identities for Azure resources?</a></p> -</li> -<li> -<p>register and manage applications in Azure AD</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app">Quickstart: Register an application with the Microsoft identity platform</a></p> -</li> -</ul> -<p><strong><u><span style="font-size: large;">Implement Solutions for Apps (10-15%)</span></u></strong></p> -<p><strong><span style="font-size: medium;">Implement an application infrastructure</span></strong></p> -<ul> -<li> -<p>create and configure Azure App Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/quickstart-dotnetcore?tabs=netcore31&amp;pivots=platform-linux">Quickstart: Create an ASP.NET Core web app in Azure</a></p> -</li> -<li> -<p>create an App Service Web App for Containers</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/deploy-run-container-app-service/">Deploy and run a containerized web app with Azure App Service</a></p> -</li> -<li> -<p>create and configure an App Service plan</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/app-service-plan-manage">Manage an App Service plan in Azure</a></p> -</li> -<li> -<p>configure an App Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/configure-common">Configure an App Service app in the Azure portal</a></p> -</li> -<li> -<p>configure networking for an App Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/web-sites-integrate-with-vnet">Integrate your app with an Azure virtual network</a></p> -</li> -<li> -<p>create and manage deployment slots</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/deploy-staging-slots">Set up staging environments in Azure App Service</a></p> -</li> -<li> -<p>implement Logic Apps</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/logic-apps/quickstart-create-first-logic-app-workflow">Quickstart: Create your first Logic Apps workflow – Azure portal</a></p> -</li> -<li> -<p>implement Azure Functions</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-azure-function">Create your first function in the Azure portal</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement container-based applications </span></strong></p> -<ul> -<li> -<p>create a container image</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/container-registry/container-registry-quickstart-task-cli">Quickstart: Build and run a container image using Azure Container Registry Tasks</a></p> -</li> -<li> -<p>configure Azure Kubernetes Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/aks/kubernetes-walkthrough-portal">Quickstart: Deploy an Azure Kubernetes Service (AKS) cluster using the Azure portal</a></p> -</li> -<li> -<p>publish and automate image deployment to the Azure Container Registry</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/container-instances/container-instances-using-azure-container-registry">Deploy to Azure Container Instances from Azure Container Registry</a></p> -</li> -<li> -<p>publish a solution on an Azure Container Instance</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/container-instances/container-instances-quickstart-portal">Quickstart: Deploy a container instance in Azure using the Azure portal</a></p> -</li> -</ul> -<p><strong><u>Implement and Manage Data Platforms (10-15%)</u></strong></p> -<p><strong><span style="font-size: medium;">Implement NoSQL databases</span></strong></p> -<ul> -<li> -<p>configure storage account tables</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/tables/table-storage-quickstart-portal">Quickstart: Create an Azure Storage table in the Azure portal</a></p> -</li> -<li> -<p>select appropriate CosmosDB APIs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/choose-api-for-cosmos-db/">Choose the appropriate API for Azure Cosmos DB</a></p> -</li> -<li> -<p>set up replicas in CosmosDB</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cosmos-db/distribute-data-globally">Distribute your data globally with Azure Cosmos DB</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement Azure SQL databases</span></strong></p> -<ul> -<li> -<p>configure Azure SQL database settings</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-sql/database/single-database-create-quickstart?tabs=azure-portal">Quickstart: Create an Azure SQL Database single database</a></p> -</li> -<li> -<p>implement Azure SQL Database managed instances</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-sql/managed-instance/sql-managed-instance-paas-overview">What is Azure SQL Managed Instance?</a></p> -</li> -<li> -<p>configure HA for an Azure SQL database</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-sql/database/high-availability-sla">High availability for Azure SQL Database and SQL Managed Instance</a></p> -</li> -<li> -<p>publish an Azure SQL database</p> -</li> -</ul> - - - + http://localhost:1313/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ + I recently passed the AZ-303 exam. Below are some of the resources I used to prepare for the exam. In addition to the links below, I also used Alan Rodrigues’ course on Udemy. https://www.udemy.com/course/az-102-azure-administrator-certification-transition/ The Udemy course and Microsoft Docs are enough to pass the exam. The course has some good practice exams and labs that align well with what you’ll see on the real exam regarding difficulty. I was scoring in the high 90’s on the Udemy exams. + Azure AD Sync &#8211; Set-MsolDirSyncEnabled : You cannot turn off Active Directory synchronization. - https://rnemeth90.github.io/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ + http://localhost:1313/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ Thu, 26 Nov 2020 16:31:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ - <p>I recently ran into a situation in my lab environment that required I resync all (2000+) user accounts to Azure AD. Though this sounds complex and daunting, its actually quite simple. T</p> -<p>The basic steps involve disabling sync, and then removing the user objects. This can all be done with two PowerShell commands:</p> -<p>1) Set-MsolDirSyncEnabled -EnableDirSync $false</p> -<p><a href="https://lh3.googleusercontent.com/-rGK18FXw7ns/X7_WthQR0CI/AAAAAAAAyCM/gg7MsY2fcVIcWMMbvxYzPpbpPyKwgHP8ACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image.png" alt=""></a></p> -<p>2) Get-MsolUser -All | Remove-MsolUser -force</p> -<p><a href="https://lh3.googleusercontent.com/-miyfN7OISGo/X7_WzDCc6iI/AAAAAAAAyCQ/PtHURTTVMQ4uypzO7L1UaLfyEs0fpYGdACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-1.png" alt=""></a></p> -<p>The account that you are currently running the commands as will not be removed.</p> -<p>To enable Azure AD Sync, you simply reverse the boolean operation on the Set-MsolDirSyncEnabled cmdlet above. However, I ran into an issue when trying to enable Azure AD Sync.</p> -<p><a href="https://lh3.googleusercontent.com/-R1TPVgYaEBE/X7_XM5_ljKI/AAAAAAAAyCY/VIJZnlgNEPQbhL9p3D0J3XsekBrGiNS3QCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-2.png" alt=""></a></p> -<p>After some research, it turns out you must wait a period of time (up to 12 hours in some cases) before you can make a second change to the Azure AD Sync status. This error simply means that we made a recent change to Azure AD Sync, and we must wait before making another change. To prove this, there is a “DirectorySynchronizationStatus” member for the Get-MsolCompanyInformation cmdlet. If we take a look at this member, we can see the status is “PendingDisabled”.</p> -<p><a href="https://lh3.googleusercontent.com/-0OBwKDDD5xQ/X7_X1bBxXjI/AAAAAAAAyCk/FyRlaMpCDT4aBe08TL_8sLiwUBnHkcPJQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-3.png" alt=""></a></p> -<p>Check the status of this periodically over the next 12 hours or so, and once it says “Enabled” or “Disabled”, you should be able to change the state once more.</p> - - - + http://localhost:1313/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ + I recently ran into a situation in my lab environment that required I resync all (2000+) user accounts to Azure AD. Though this sounds complex and daunting, its actually quite simple. T The basic steps involve disabling sync, and then removing the user objects. This can all be done with two PowerShell commands: 1) Set-MsolDirSyncEnabled -EnableDirSync $false 2) Get-MsolUser -All | Remove-MsolUser -force The account that you are currently running the commands as will not be removed. + Azure VM Scale Set &#8211; Get Instance IP Address - https://rnemeth90.github.io/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ + http://localhost:1313/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ Thu, 19 Nov 2020 18:07:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ - <p>If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal.</p> -<p>There are a few options we have for retrieving information about a VMSS and its instances without using the Azure Portal. We can use PowerShell or the Azure CLI. Being that I am constantly flipping between Windows and Linux, I will detail both here.</p> -<p>You will need to have the AZ module installed. To install this module, simple open PowerShell (as admin) and type in “Install-Module -Name az”. To get the IP address of the instances within a scale set, use the following script:</p> -<p><a href="https://github.com/rnemeth90/Get-VmssInstanceIpAddress">https://github.com/rnemeth90/Get-VmssInstanceIpAddress</a></p> -<p>You can also use the Azure CLI to obtain individual instance IP addresses. This method is much simpler than PowerShell, and only requires one line of code:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>az vmss nic list –resource-group myResourceGroup –vmss-name myVmss | grep –w “privateIpAddress” -</span></span></code></pre></div> - - + http://localhost:1313/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ + If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal. There are a few options we have for retrieving information about a VMSS and its instances without using the Azure Portal. + Azure Policy &#8211; Allowed Locations for Resource Deployment - https://rnemeth90.github.io/posts/2020-11-17-azure-policy-allowed-locations-for/ + http://localhost:1313/posts/2020-11-17-azure-policy-allowed-locations-for/ Tue, 17 Nov 2020 17:52:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-17-azure-policy-allowed-locations-for/ - <p>Azure Policy allows us to control what actions users can perform regarding creating and managing resources in Azure. We can define policies for naming standards, require that certain extensions be installed on virtual machines, audit various resources for certain configurations… the possibilities are endless.</p> -<p>In this article, well focus on defining what locations users can deploy resources in. To get started, login to the Azure Portal and search for “Policy”.</p> -<p><a href="https://lh3.googleusercontent.com/-7ao7r-Xj5Kk/X7QNKSrY3AI/AAAAAAAAx-8/xIUtw-pRL20pSMxsOaGUwnk-9XHSpup9ACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-4.png" alt=""></a></p> -<p>Click on “Definitions”. Here you will find several built-in definitions that can be applied to your resources. Definitions are a json template containing the logic for what you want to accomplish. It is worth investing some time to look through these built-in definitions.</p> -<p>In the “search” field, type in “location”. Then, click on the “Allowed Locations” definition.</p> -<p><a href="https://lh3.googleusercontent.com/-5FJ3EcMnG8k/X7QNP-1-5II/AAAAAAAAx_A/TH4cr4SxgbQiNVdoRlDyB_F4ukOV5bJvwCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-5.png" alt=""></a></p> -<p>Here you can see the json content of the definition. The “policyRule” section is the bread and butter of the definition. In this particular example, the policyRule states that if the location that the user is deploying a resource to is NOT a) in the list of allowed locations, b) global, or c) a b2c directory, then deny the deployment.</p> -<p><a href="https://lh3.googleusercontent.com/-WKsYDX4nao4/X7QNVcSEVJI/AAAAAAAAx_E/HIbPqLSHfBIjYRRZI27X7cLjStbnXlqaQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-6.png" alt=""></a></p> -<p>Next, click on “Assign”.</p> -<p><a href="https://lh3.googleusercontent.com/-Qg35QQcnGZY/X7QNarWcMbI/AAAAAAAAx_M/Et9yP9ZNyXEU1Ow8m5BwZG8RcTBaadInQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-7.png" alt=""></a></p> -<p>You can assign the policy to a subscription or resource group. You can also create exclusions in this same window, and enable or disable the policy.</p> -<p><a href="https://lh3.googleusercontent.com/-16qmOT43oKo/X7QNfuX4KVI/AAAAAAAAx_Q/_0wak5v2CCA2yIrwLalJgvhCnBCCEJcOQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-8.png" alt=""></a></p> -<p>Click “Next”, and on the Parameters page, choose the allowed locations from the drop down menu. Then click next.</p> -<p>Azure Policy has the capability to remediate non-compliant resources. An example would be having a policy that requires anti-virus be installed on all servers. If Azure Policy detected a server that did NOT have anti-virus installed, it would use a managed identity to install AV software on the server. This particular policy does not need a remediation action, so we will just click “Next” here.</p> -<p>On the Review + Create window, review the resource and then click “Create”.</p> -<p>Back on the Azure Policy blade, select “Assignments”. We can now see that our new policy is assigned.</p> -<p><a href="https://lh3.googleusercontent.com/-K8ofsNe1ALY/X7QNrf8dfkI/AAAAAAAAx_c/3R0DRk4LKWYcGP6-LJ3vgRUcUOQaZ6r3ACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-9.png" alt=""></a></p> -<p>Back on the “Overview” page, you can track compliance for the policy. We can see here that compliance for the “Allowed Locations” policy assignment has not yet been started. This typically takes an hour or so before the compliance state is updated.</p> -<p><a href="https://lh3.googleusercontent.com/-S-zq_cWBh7Y/X7QNvjMRUrI/AAAAAAAAx_k/CG194fTLqKIHqTNMmCyJzM4W9HJ_d6aPgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-10.png" alt=""></a></p> -<p>Click on the Policy to get a more detailed view of compliance, view the definition, edit the assignment, and even create exemptions.</p> -<p><a href="https://lh3.googleusercontent.com/-9sdnYSeQZ7A/X7QNzt8EEdI/AAAAAAAAx_o/3-2_eyPVjxIFSINg8IzEhKwZzWGUgf9NQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-11.png" alt=""></a></p> - - - + http://localhost:1313/posts/2020-11-17-azure-policy-allowed-locations-for/ + Azure Policy allows us to control what actions users can perform regarding creating and managing resources in Azure. We can define policies for naming standards, require that certain extensions be installed on virtual machines, audit various resources for certain configurations… the possibilities are endless. In this article, well focus on defining what locations users can deploy resources in. To get started, login to the Azure Portal and search for “Policy”. + Replicate an Azure VM Image Between Regions - https://rnemeth90.github.io/posts/2020-11-03-replicate-azure-vm-image-between-regions/ + http://localhost:1313/posts/2020-11-03-replicate-azure-vm-image-between-regions/ Tue, 03 Nov 2020 20:15:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-03-replicate-azure-vm-image-between-regions/ - <p>Let’s say you have a VM in Azure North Central. You created this VM from a custom image that you maintain in an Azure image repository. Now, what if you wanted to create that same VM in Azure South Central, and use the same reference image? A standard image repository is limited to the region that it exists in. The answer here is to create a Shared Image Library, add the image to it, and then configure the image to replicate to other Azure regions.</p> -<p>This article assumes you already have an image.</p> -<p>First, create a Shared Image Gallery in Azure. Browse to the Azure portal (<a href="https://portal.azure.com/">https://portal.azure.com</a>), and (from the home page) click “create a resource”.</p> -<p><a href="https://lh3.googleusercontent.com/-LQbh5w9zFN0/X6G5qBxrC1I/AAAAAAAAx5I/QH95DqgHJzUgkC5YhWqmQ_pOXmCygVHwQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-12.png" alt=""></a></p> -<p>Search for “Shared Image Gallery” and then click “Create”.</p> -<p>Configure a subscription, resource group, and then name the Shared Image Gallery and configure what region you want it to live in. You will want to create it in the same region as your standard image repository.</p> -<p><a href="https://lh3.googleusercontent.com/-61hBPxzwPzI/X6G5w_C7-iI/AAAAAAAAx5M/GVHvFpgE2WQwupil-OSd7nZ2nJEZRI0MgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-13.png" alt=""></a></p> -<p>If you want to assign some tags to this new resource, continue to the next page. Otherwise, click “Review + Create”.</p> -<p><a href="https://lh3.googleusercontent.com/-OCPyDsSbRYo/X6G52usmBSI/AAAAAAAAx5Q/nZJuX9YZzNsWU4aJwGNkZ5kulaXb5mcGgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-14.png" alt=""></a></p> -<p>On the final page, if the validation is successful, click “Create”.</p> -<p><a href="https://lh3.googleusercontent.com/-gCwUW-ntoKA/X6G56AAogVI/AAAAAAAAx5Y/wcUUn2_P68MNl5wCWIqQTYGRqEvJMJm6QCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-15.png" alt=""></a></p> -<p>It should take less than a minute to create the shared image gallery. Once its created, click “Go to resource”.</p> -<p><a href="https://lh3.googleusercontent.com/-mZQpi2f85MQ/X6G5-7FGFUI/AAAAAAAAx5c/vPOG47n736gp87Z2rftfjvL9OcGolOGxACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-16.png" alt=""></a></p> -<p>In the shared image gallery blade, click “Add new image definition”.</p> -<p><a href="https://lh3.googleusercontent.com/-qSWGjKuUMp4/X6G6CZsRAXI/AAAAAAAAx5g/-LYCx4Qmf98k2mbjM9CC-8mKVA-zp-8rACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-17.png" alt=""></a></p> -<p>On the next page, select the region where your existing image repository lives, give the image definition a name, and then fill out the rest of the information as needed. The publisher will typically be the name of your company/organization. The offer will typically be set to the name of the overall application, being that servers typically host one piece of an application (example: database servers vs. application servers). The SKU will typically be set to the name of the component within the application (for example, a web server or database server).</p> -<p><a href="https://lh3.googleusercontent.com/-4ZaK5D-Y0FE/X6G6G3n8KsI/AAAAAAAAx5k/jd18bOcFQ1kP62-0zE1Vuhwx6WpRnEyGwCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-18.png" alt=""></a></p> -<p>Next, configure an image version. This should use the typical semantic format used in software development (major version, minor version, patch level). I will typically substitute the patch level with the date the image was captured. Probably not a best practice, but something that has served me well in the past.</p> -<p>Next, select the source image. This will be the image that you are copying from your standard image repository. You can also configure an end of life date for the image version here if you wish. In the “Target Regions” section at the bottom, select the region where you plan to create the new VM. Also select the target storage account type.</p> -<p><a href="https://lh3.googleusercontent.com/-6F59gxbQ7ws/X6G6PI4qVeI/AAAAAAAAx5w/x2SCNG8PawMUZRQS6q55kAvgsOfD8bnPACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-19.png" alt=""></a></p> -<p>You can configure some publishing options and tags on the following pages. Though, it is not required. Click “Review + create”. <span style="mso-spacerun: yes;"> </span><span style="mso-spacerun: yes;"> </span>After the validation passes, click “Create”.</p> -<p><a href="https://lh3.googleusercontent.com/-CyzD7E88UVU/X6G6TQGRu6I/AAAAAAAAx54/2yHQrYIFUp8P8JyWMuEbsfFL47UW8Il0ACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-20.png" alt=""></a></p> -<p>This process will take a few minutes to complete. Once its finished, click on “go to resource”. You now have an image that is available to be deployed in the north central region or the south central region.</p> - - - + http://localhost:1313/posts/2020-11-03-replicate-azure-vm-image-between-regions/ + Let’s say you have a VM in Azure North Central. You created this VM from a custom image that you maintain in an Azure image repository. Now, what if you wanted to create that same VM in Azure South Central, and use the same reference image? A standard image repository is limited to the region that it exists in. The answer here is to create a Shared Image Library, add the image to it, and then configure the image to replicate to other Azure regions. + Reset GRUB/root Password for vCenter/PSC Appliance - https://rnemeth90.github.io/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ + http://localhost:1313/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ Sat, 31 Oct 2020 01:22:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ - <p>In Redhat/Fedora/Cent, GRUB can be protected by running the grub-md5-crypt command and pasting the outputted password hash into the grub.conf file. vSphere 6.0 password protects grub by default. If you change the root password in the VAMI, the GRUB password is changed to match. If you do not change the root password, the GRUB password is “vmware”.</p> -<p>To reset the GRUB password, we need to boot into a Cent or Redhat live CD. The ISO can be obtained here: <a href="https://www.centos.org/download/">https://www.centos.org/download/</a>. Its best to upload the ISO to a datastore that the appliance has access to.</p> -<p>Stop the appliance and attach the ISO:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image.png" alt=""></p> -<p>Be sure to select the “Connect at Power On” option. Boot the VM into the ISO and select the “Troubleshooting” option.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-1.png" alt=""> -Next, choose “Rescure a Red hat (or CentOS depending on your ISO) Enterprise Linux System”</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-2.png" alt=""></p> -<p>Select “Continue” to mount the VCSA 6.0’s root filesystem in Read/write mode under /mnt/sysimage. RHEL 7.2 is capable to detect the VCSA’s root volume and mounts it.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-3.png" alt=""></p> -<p>The VCSA root filesystem is mounted under /mnt/sysimage and you can now access (and modify) it using the shell. Navigate to /mnt/sysimage/boot and list the contents. You’ll see we now have access to the grub directory:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-4.png" alt=""></p> -<p>cd to the grub directory and list the contents. Look for a file called “menu.lst”. This file holds the grub boot loader password. Open this file with vi by typing “vi menu.lst”. Navigate to the line beginning with “password” using the arrow keys, and then type “dd” to remove the line.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-5.png" alt=""> -You can then save the file by pressing “:wq” (without quotes). You can now cat the file and see that the password has been removed.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-6.png" alt=""></p> -<p>Exit the shell (this will reboot the server). Detach the ISO and boot the appliance. Once the system is booted, stop the VCSA in the GRUB menu (by pressing the escape key during boot) to break the OS root password.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-7.png"></a> -Press “e” to edit the boot commands for the kernel.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-8.png" alt=""></p> -<p>Append “init=/bin/bash” to the line in this step and press enter.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-9.png" alt=""></p> -<p>Press “b” to boot the system.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-10.png" alt=""></p> -<p>You will now boot into a bash shell where you can set the root password.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-11.png" alt=""></p> -<p>Once this is done, exit the shell by typing “exit”. You can now boot the appliance and login with your new root password.</p> - - - + http://localhost:1313/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ + In Redhat/Fedora/Cent, GRUB can be protected by running the grub-md5-crypt command and pasting the outputted password hash into the grub.conf file. vSphere 6.0 password protects grub by default. If you change the root password in the VAMI, the GRUB password is changed to match. If you do not change the root password, the GRUB password is “vmware”. To reset the GRUB password, we need to boot into a Cent or Redhat live CD. + Deploy a New ADDS Forest on Server 2019 Core - https://rnemeth90.github.io/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ + http://localhost:1313/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ Sat, 31 Oct 2020 01:02:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ - <p>Prerequisites:</p> -<p>Change server name and IP address -Configure time settings and NTP</p> -<p>In this post we will be reviewing the basic installation of the Active Directory Domain Services role and setup of a new forest on Windows Server Core 2019.</p> -<p>To get started, login to your server with administrator privileges. You will first need to type in “powershell” in the cmd prompt to start powershell. Once you do that, type in the following command to install the Active Directory Domain Services role:</p> -<p><a href="https://lh3.googleusercontent.com/-LnSTbXjG2Hc/X5y3R3F-eWI/AAAAAAAAx2A/lWQBpA44Dmo-Jpbck2iPmgibU6z0DM1YwCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-12.png" alt=""></a></p> -<p>After installing the role, we’ll continue by creating a new ADDS Forest and promoting this server to the primary domain controller.</p> -<p>First, we’ll need to gather a password. This password will not be used for a domain user account. The local administrator on this server will become the domain administrator account for the domain. The password we’re gathering in the next step will be used for Directory Services Restore Mode (DSRM). DSRM is a recovery mode used to recover domain controllers that won’t boot up. We technically only need a password, not a username for this account.</p> -<p>Type in the following:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$cred = Get-Credential -</span></span></code></pre></div><p>In the username field for the credentials prompt below, just type in anything you want, as the value will not be used. This prompt will store our username/password in a variable object. We can then access the password within the credential object by typing:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$cred.password -</span></span></code></pre></div><p>We can see that this password is stored as a secure string object. Let’s continue on with the Directory Services installation.</p> -<p><a href="https://lh3.googleusercontent.com/-n-W0yvwr2Zs/X5y3X64NjZI/AAAAAAAAx2E/rx5urA7p_NMl3peX5g0J7Ax7biWwNADAgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-13.png" alt=""></a></p> -<p><a href="https://lh3.googleusercontent.com/-0k-aZrMhyGw/X5y3ckH10pI/AAAAAAAAx2I/FS56uvXCirAaBHKwWmIRQ4xIGU_jp_GFwCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-14.png" alt=""></a></p> -<p>Once we have our credential variable, we can install a new forest and domain controller using the command below. Let us break down what this cmd is doing:</p> -<p><a href="https://lh3.googleusercontent.com/-OF_HVfCPZIM/X5y3ijEA5YI/AAAAAAAAx2M/0vMV3CJczT8D3q5x8hzPAZVSL5DycplBACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-15.png" alt=""></a></p> -<p>Install-ADDSForest: The powershell cmdlet to create a new forest and domain controller</p> -<p>-DomainName: The domain name to be used for the forest</p> -<p>-DomainNetBiosName: The domain “Short name” to be used for the forest. This is the value used when you type in a username in the domainusername format. Example “myDomainbgates”.</p> -<p>-SafeModeAdministratorPassword: The value we captured in our credential prompt above. This is used for Directory Services Restore Mode. This mode can be accessed by pressing F8 while the server is booting. It is commonly used for recovering a failed domain controller.</p> -<p>-DatabasePath: The path for the Active Directory database. It’s a best practice to put this database on its own disk.</p> -<p>-LogPath: The directory for ADDS log files</p> -<p>-DomainMode: The domain functional level. The domain functional level specifies the attributes and capabilities available to objects within the domain. The higher the level you choose, the more features will be available to you.</p> -<p>-ForestMode: The forest functional level. Similar to the domain functional level but applies to the entire forest.</p> -<p>-InstallDNS: Install the DNS role alongside the ADDS role.</p> -<p>-WhatIf: This is a powershell “thing”. Most cmdlets have the “whatif” parameter. It basically allows you to run the cmdlet in “test” mode without actually making any changes to your environment. Once you’re happy with the output, you can remove the “whatif” parameter and run the command to install ADDS and promote this server to a domain controller.</p> - - - + http://localhost:1313/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ + Prerequisites: Change server name and IP address Configure time settings and NTP In this post we will be reviewing the basic installation of the Active Directory Domain Services role and setup of a new forest on Windows Server Core 2019. To get started, login to your server with administrator privileges. You will first need to type in “powershell” in the cmd prompt to start powershell. Once you do that, type in the following command to install the Active Directory Domain Services role: + Could not connect to VMware Directory Service via LDAP when Deploying New vCenter Appliance - https://rnemeth90.github.io/posts/2020-10-28-could-not-connect-to-vmware-directory/ + http://localhost:1313/posts/2020-10-28-could-not-connect-to-vmware-directory/ Wed, 28 Oct 2020 13:51:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-28-could-not-connect-to-vmware-directory/ - <p>Problem:</p> -<p>Deploying a brand new vCSA 6.7 appliance results in the following error during the second stage of the deployment.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h29_02.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h29_02.png" alt=""></a><span style="text-align: left;"> </span></p> -<p>Solution:</p> -<p>This problem is almost always caused by DNS resolution. Once you create the appropriate A and PTR record for your appliance on a LOCAL DNS server, you should be to successfully complete the deployment. Local DNS resolution is required, you cannot use a public DNS server while installing vCenter. For example, 8.8.8.8 will not work.</p> -<p>Since you have already completed Stage 1 of the deployment, you can login to the appliance via SSH and update the DNS settings. This will only work if you chose to enable SSH during Stage 2 of the deployment.</p> -<p>SSH to the appliance and run “/opt/vmware/share/vami/vami_config_net” (without quotes). Choose option 4 to update DNS settings and option 3 to update the hostname (if necessary). The deployment wizard states that a hostname is optional, but it is actually required. I have never had a successful deployment without specifying the hostname.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h33_18.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h33_18.png" alt=""></a></p> -<p>You can then verify the DNS settings have been updated in the resolve.conf:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h33_57.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h33_57.png" alt=""></a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_08h47_36.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_08h47_36.png" alt=""></a></p> - - - + http://localhost:1313/posts/2020-10-28-could-not-connect-to-vmware-directory/ + Problem: Deploying a brand new vCSA 6.7 appliance results in the following error during the second stage of the deployment. Solution: This problem is almost always caused by DNS resolution. Once you create the appropriate A and PTR record for your appliance on a LOCAL DNS server, you should be to successfully complete the deployment. Local DNS resolution is required, you cannot use a public DNS server while installing vCenter. For example, 8. + Cisco AnyConnect &#8211; VPN Establishment Capability from a Remote Desktop is Disabled - https://rnemeth90.github.io/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ + http://localhost:1313/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ Wed, 07 Oct 2020 13:28:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ - <p>I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution.</p> -<p><a href="https://lh3.googleusercontent.com/-BYApW8vZjV8/X33B2Or4D7I/AAAAAAAAxuY/hWQwpE-fqo4xInAsx9vyUvzDJXqxe68QQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-16.png" alt=""></a></p> -<p>Upon installation, AnyConnect pulls down a profile from the ASA containing several settings. This profile is in xml format and is located (on a Windows machine) at %programdata%CiscoCisco AnyConnect Secure Mobility ClientProfileAnyConnectProfile.xsd.</p> -<p>To resolve this issue and connect to your VPN, open this file with notepad (or any text editor, run as admin), search for the “WindowsVPNEstablishment” tag, and modify the value. The default value is “LocalUsersOnly”, you will need to change it to “AllowRemoteUsers”. Save and close the file, then restart the machine.</p> -<p>BEFORE:</p> -<p><a href="https://lh3.googleusercontent.com/-izGUUyhtWyM/X33Bh8YdqGI/AAAAAAAAxuQ/rBbXsqWhe5wZYoGmjXwyyidGmu1kCNVmgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-17.png" alt=""></a></p> -<p>AFTER:</p> -<p><a href="https://lh3.googleusercontent.com/-wFFu1JOXymQ/X33CVp0cImI/AAAAAAAAxug/fibXC6JHmkkilFtWv8641x20flapCibYACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-18.png" alt=""></a></p> - - - + http://localhost:1313/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ + I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution. Upon installation, AnyConnect pulls down a profile from the ASA containing several settings. This profile is in xml format and is located (on a Windows machine) at %programdata%CiscoCisco AnyConnect Secure Mobility ClientProfileAnyConnectProfile.xsd. To resolve this issue and connect to your VPN, open this file with notepad (or any text editor, run as admin), search for the “WindowsVPNEstablishment” tag, and modify the value. + Error When Reinstalling DirSync - https://rnemeth90.github.io/posts/2019-01-14-error-when-reinstalling-dirsync/ + http://localhost:1313/posts/2019-01-14-error-when-reinstalling-dirsync/ Mon, 14 Jan 2019 21:47:04 +0000 - - https://rnemeth90.github.io/posts/2019-01-14-error-when-reinstalling-dirsync/ - <p>Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/1.png" alt=""></a></p> -<p>I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do:</p> -<p>• Uninstall Windows Azure Active Directory Sync tool and reboot</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/2.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/2.png" alt=""></a></p> -<p>• Remove this directory and all subfolders: C:\Program Files\Windows\Azure Active Directory Sync</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/3.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/3.png" alt=""></a></p> -<p>• If you created a domain account to use for DirSync, remove it. Also remove the Office 365 account you created. -• Delete the Group accounts that the DirSync wizard created. Their names all begin with “FIM”</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/4.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/4.png" alt=""></a></p> -<p>• Uninstall MSSQL -• Delete the MSSQL directory: C:Program FilesMicrosoft SQL Server -• Reboot! -• You should be able to install and configure DirSync now.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/5.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/5.png" alt=""></a></p> - - - + http://localhost:1313/posts/2019-01-14-error-when-reinstalling-dirsync/ + Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process: I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do: + Active Directory Migration Toolkit &#8211; The RPC Server is Unavailable (hr=0x800706ba) - https://rnemeth90.github.io/posts/2018-08-21-active-directory-migration-toolkit-rpc/ + http://localhost:1313/posts/2018-08-21-active-directory-migration-toolkit-rpc/ Tue, 21 Aug 2018 17:34:00 +0000 - - https://rnemeth90.github.io/posts/2018-08-21-active-directory-migration-toolkit-rpc/ - <p>When migrating computer objects using the Active Directory Migration Tool, you may encounter the following error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_09.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_09.png" alt=""></a></p> -<p>In addition, the Migration Log may show the following error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_20.png" alt=""></a></p> -<p>This is typically caused by a host-side firewall. To resolve this, deploy a GPO to disable the Windows firewall prior to migrating the computer account. I like to create a special OU for computers (I typically name it “PreMigration”) that I will move computer objects to prior to migrating them. This OU will have two policies applied. One to disable the Windows Firewall and another to start the Remote Registry service. Both are required for the computer object to successfully migrate.</p> - + http://localhost:1313/posts/2018-08-21-active-directory-migration-toolkit-rpc/ + When migrating computer objects using the Active Directory Migration Tool, you may encounter the following error: In addition, the Migration Log may show the following error: This is typically caused by a host-side firewall. To resolve this, deploy a GPO to disable the Windows firewall prior to migrating the computer account. I like to create a special OU for computers (I typically name it “PreMigration”) that I will move computer objects to prior to migrating them. - Azure Site Recovery &#8211; VMware-to-Azure: Wrong IP address discovered for VM - https://rnemeth90.github.io/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ + http://localhost:1313/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ Tue, 21 Aug 2018 17:26:00 +0000 - - https://rnemeth90.github.io/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ - <p>When replicating virtual machines from VMware to Azure using Site Recovery, you may encounter an issue where the Configuration server discovers the wrong IP address for a VM. This can be caused by stale entries within the infrastructurevms MySQL table that is used by ASR to track VM attributes.</p> -<p>To resolve this issue, you first need to disable replication for the VM in the Azure Portal.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-21_13h20_26.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-21_13h20_26.png" alt=""></a></p> -<p>Next, login to your ASR Configuration Server and open a CMD prompt as administrator. Browse to the bin directory for your ASR installation. For example, in my case ASR is installed on the E: partition under the following directory:</p> -<p>E:\Program Files (x86)Microsoft Azure Site Recoveryhomesvsystemsbin</p> -<p>Type in this command to remove the VM from the ASR database (replace IP address with the IP of your VM):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-perl" data-lang="perl"><span style="display:flex;"><span>perl Unregister<span style="color:#f92672">-</span>ASRComponent<span style="color:#f92672">.</span>pl <span style="color:#f92672">-</span>IPAddress <span style="color:#ae81ff">10.0.0.4</span> <span style="color:#f92672">-</span>Component Source -</span></span></code></pre></div><p>That’s it. You should now be able to reconfigure replication for the VM, and ASR will discover the correct info about the VM.</p> - - - + http://localhost:1313/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ + When replicating virtual machines from VMware to Azure using Site Recovery, you may encounter an issue where the Configuration server discovers the wrong IP address for a VM. This can be caused by stale entries within the infrastructurevms MySQL table that is used by ASR to track VM attributes. To resolve this issue, you first need to disable replication for the VM in the Azure Portal. Next, login to your ASR Configuration Server and open a CMD prompt as administrator. + Azure AD Connect No-Start-Connection - https://rnemeth90.github.io/posts/2018-07-26-azure-ad-connect-no-start-connection/ + http://localhost:1313/posts/2018-07-26-azure-ad-connect-no-start-connection/ Thu, 26 Jul 2018 12:22:00 +0000 - - https://rnemeth90.github.io/posts/2018-07-26-azure-ad-connect-no-start-connection/ - <p>This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working.</p> -<p>After forcing the sync, I opened miisclient and noticed some strange errors. We sync multiple on-prem AD forests to Azure AD, and the status for one of them was “no-start-connection”. That error in itself does not seem significant to me. However, after clicking on the “failed-connection” link in the Connection Status pane, things became much more clear.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_05.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_05.png" alt=""></a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_18.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_18.png" alt=""></a></p> -<p>The domain controllers for the forest in question are in a datacenter that is geographically separated from the datacenter that our Azure AD Sync server lives in. The two sites are connected via a S2S VPN.</p> -<p>There was obviously some type of connection issue between our two datacenters. In my case, the issue was transient, and resolved itself after a few minutes. But if you’re experiencing this error message, check your L2/L3 connection. Also, verify DNS is working and someone didn’t make changes to your firewall(s). Just walk up or down the OSI model and you’ll eventually find the problem.</p> - - - + http://localhost:1313/posts/2018-07-26-azure-ad-connect-no-start-connection/ + This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working. After forcing the sync, I opened miisclient and noticed some strange errors. + Azure AD Connect Health: Latest Data is not Available in Azure Portal - https://rnemeth90.github.io/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ + http://localhost:1313/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ Wed, 18 Jul 2018 16:38:00 +0000 - - https://rnemeth90.github.io/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ - <p>I recently had to create a new Azure AD Connect server, and found that it was not able to report health status in the Azure Portal. After some troubleshooting/research, I was able to get the health status report working by registering the health agent on the server with Azure AD Health Services. Doing this involves running one PowerShell cmdlet on your AD Connect server and providing global administrator credentials.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_56.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_56.png" alt=""></a></p> -<p>First, let’s test the status of the agent communication:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_19.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_19.png" alt=""></a></p> -<p>If you do not receive any errors, that means the Azure AD Connect Health agent on your server is able to successfully communicate with the cloud service. Now, let’s register the agent:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_05.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_05.png" alt=""></a></p> -<p>You will be prompted for credentials. The credentials you provide need to be a global administrator account in your Azure AD tenant.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_42.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_42.png" alt=""></a></p> -<p>You should receive some output stating that the registration is successful (or it failed).</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h25_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h25_20.png" alt=""></a></p> -<p>Now, just go back to the Azure Portal and refresh the page. The message stating that the -“latest data is not available” should be gone.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h36_42.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h36_42.png" alt=""></a></p> - - - + http://localhost:1313/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ + I recently had to create a new Azure AD Connect server, and found that it was not able to report health status in the Azure Portal. After some troubleshooting/research, I was able to get the health status report working by registering the health agent on the server with Azure AD Health Services. Doing this involves running one PowerShell cmdlet on your AD Connect server and providing global administrator credentials. First, let’s test the status of the agent communication: + Removing a Forest from Azure AD Connect - https://rnemeth90.github.io/posts/2018-07-13-removing-forest-from-azure-ad-connect/ + http://localhost:1313/posts/2018-07-13-removing-forest-from-azure-ad-connect/ Fri, 13 Jul 2018 15:30:00 +0000 - - https://rnemeth90.github.io/posts/2018-07-13-removing-forest-from-azure-ad-connect/ - <p>In an organization with multiple Active Directory forests, you may want to sync objects from trusted forests. Adding trusted forests to Azure AD Sync is a simple process that I will likely cover in a future article. The focus of this post is the not-so-obvious process of removing a forest from Azure AD Connect. This can be a daunting and somewhat scary thing to do. Not fully understanding the process or having someone to guide you can leave you with thoughts like “what happens when I remove the forest from Azure AD Sync? Do on-premises objects get deleted? Are cloud objects deleted?”. I will try to answer these questions to the best of my ability and hopefully make the process simple and stress-free for you.</p> -<p>To get started, we first need to open PowerShell and disable the AD Sync scheduler. You can do this by running the “Set-ADSyncScheduler” cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h47_05.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h47_05.png" alt=""></a></p> -<p>This cmdlet is included in the ADSync PowerShell module. You may need to load the module prior to using the cmdlet:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Import-Module ADSync -</span></span></code></pre></div><p>The next step is to open FIM (miisclient) located in the install directory of Microsoft Azure AD Sync. By default, this is C:Program FilesMicrosoft Azure AD SyncUIShellmiisclient.exe. Once you have FIM open, click on the Connectors tab, then right click on the connector for the forest that you want to delete, and click “Delete”.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_26.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_26.png" alt=""></a></p> -<p>You will then be prompted, asking if you want to just delete the Connector Space, or delete the Connector and the Connector Space. The former open removes all data, but keeps the configuration in case you want to use it again later. The latter option deleted the data and the configuration. This open should only be used if you don’t plan on syncing the forest again.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_09.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_09.png" alt=""></a></p> -<p>The connector for the forest is now deleted, but what actually happens? Your on-premises objects do not get removed for the forest, and cloud objects <strong>are</strong> removed. Simple enough, right?</p> -<p>Now you just need to re-enable the AD Sync Scheduler with this cmdlet:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Set-ADSyncScheduler -SyncCycleEnabled $true -</span></span></code></pre></div><p>One last thing to mention… You may receive an email from the Microsoft Online Services Team stating that the identity synchronization failed due to a deletion threshold being met. By default, Azure AD Connect will not allow you to delete more than 500 objects in your cloud directory. This is to protect you from making a careless (potentially resume generating) mistake. The email will look something like this:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h56_04.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h56_04.png" alt=""></a></p> -<p>If you are certain that you want to proceed with deleting the objects, here are the steps:</p> -<ol> -<li> -<p>Disable the deletion threshold protection. Open PowerShell on your Azure AD Sync server and type in this cmdlet: Disable-ADSyncExportDeletionThreshold. You will be prompted for credentials, sign-in with an Azure AD Global Admin account.</p> -</li> -<li> -<p>Open FIM (miisclient), and click on the “Connectors” button at the top of the window. Right click on the connector of type “Windows Azure Active Directory”, and select “Run…”.</p> -</li> -</ol> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_39.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_39.png" alt=""></a></p> -<ol start="3"> -<li>Next, click Export and then click Ok.</li> -</ol> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_58.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_58.png" alt=""></a></p> -<ol start="4"> -<li> -<p>Allow the connector to run. This will take a few minutes. You can monitor the progress by clicking the Operations button.</p> -</li> -<li> -<p>Once this completes, you need to re-enable the deletion threshold. You can do this by running this cmdlet: <span style="background: #F9F9F9;"></p> -</li> -</ol> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Enable-ADSyncExportDeletionThreshold -DeletionThreshold <span style="color:#ae81ff">500</span>. -</span></span></code></pre></div><p>You will be prompted for credentials again. Just type in your Azure AD Global Admin creds. You can even lower the threshold if you’d like. I set mine to 100.</p> - - - + http://localhost:1313/posts/2018-07-13-removing-forest-from-azure-ad-connect/ + In an organization with multiple Active Directory forests, you may want to sync objects from trusted forests. Adding trusted forests to Azure AD Sync is a simple process that I will likely cover in a future article. The focus of this post is the not-so-obvious process of removing a forest from Azure AD Connect. This can be a daunting and somewhat scary thing to do. Not fully understanding the process or having someone to guide you can leave you with thoughts like “what happens when I remove the forest from Azure AD Sync? + Remove Stubborn PSC or vCenter Appliance from an SSO Domain - https://rnemeth90.github.io/posts/2017-11-08-remove-stubborn-psc-or-vcenter/ + http://localhost:1313/posts/2017-11-08-remove-stubborn-psc-or-vcenter/ Wed, 08 Nov 2017 07:56:00 +0000 - - https://rnemeth90.github.io/posts/2017-11-08-remove-stubborn-psc-or-vcenter/ - <p>While attempting to decommission one of our vCenter sites, I ran into an issue removing one of the PSCs. This site consisted of two PSCs and one vCenter appliance. I removed the first PSC from the SSO domain successfully, and then removed the vCenter appliance. Things became a little tricky during the removal of the final PSC. This PSC did not get removed even after running the cmsso-util command. This article will detail the steps I took in decommissioning the site, as well as removing the stubborn PSC.</p> -<p>First, we need to check if vCenter is currently using the PSC we plan on decommissioning. If it is, we need to use the cmsso-util command to redirect vCenter to a different PSC. Instructions for redirecting vCenter can be found here: <a href="https://kb.vmware.com/s/article/2113917?language=en_US">https://kb.vmware.com/s/article/2113917?language=en_US</a></p> -<p>To check what PSC your vCSA is currently pointing to, browse to the Advanced Settings for the vCSA in the vSphere Web Client. Filter by this key: config.vpxd.sso.admin.uri</p> -<p>To remove a PSC or vCSA from an SSO domain, connect to a PSC via SSH and run these commands:</p> -<p>To remove a PSC from the vSphere SSO domain:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>cmsso-util unregister –node-pnid psc01.ad.vcplab.local –username administrator@your<span style="color:#ae81ff">\_</span>domain<span style="color:#ae81ff">\_</span>name –passwd vCenter<span style="color:#ae81ff">\_</span>Single<span style="color:#ae81ff">\_</span>Sign<span style="color:#ae81ff">\_</span>On<span style="color:#ae81ff">\_</span>password -</span></span></code></pre></div><p>To remove a vCSA from the vSphere SSO domain:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>cmsso-util unregister –node-pnid vcsa.ad.vcplab.local –username administrator@your<span style="color:#ae81ff">\_</span>domain<span style="color:#ae81ff">\_</span>name –passwd vCenter<span style="color:#ae81ff">\_</span>Single<span style="color:#ae81ff">\_</span>Sign<span style="color:#ae81ff">\_</span>On<span style="color:#ae81ff">\_</span>password -</span></span></code></pre></div><p>After running these commands, delete the virtual appliances. You can also verify the appliances have been removed by browsing to Administration &gt; System Configuration &gt; Nodes in the vSphere Web Client.</p> -<p>If cmsso-util fails to remove any of the nodes, you can use this command to force the removal:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>vdcleavefed -h vcsa.ad.vcplab.local -u Administrator -w Passw0rd! -</span></span></code></pre></div><p>Upon successful completion, you should see something like this:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>/usr/lib/vmware-vmdir/bin/vdcleavefed -h vcsa.ad.vcplab.local -u administrator* password: -</span></span><span style="display:flex;"><span>vdcleavefd offline <span style="color:#66d9ef">for</span> server vcsa.ad.vcplab.local -</span></span><span style="display:flex;"><span>Leave federation cleanup <span style="color:#66d9ef">done</span> -</span></span></code></pre></div><p>When specifying the username, use the SSO admin (administrator). However, do not use the full UPN (<a href="mailto:administrator@vsphere.local">administrator@vsphere.local</a>). Doing so will cause the command to fail.</p> - - - + http://localhost:1313/posts/2017-11-08-remove-stubborn-psc-or-vcenter/ + While attempting to decommission one of our vCenter sites, I ran into an issue removing one of the PSCs. This site consisted of two PSCs and one vCenter appliance. I removed the first PSC from the SSO domain successfully, and then removed the vCenter appliance. Things became a little tricky during the removal of the final PSC. This PSC did not get removed even after running the cmsso-util command. This article will detail the steps I took in decommissioning the site, as well as removing the stubborn PSC. + Exchange 2016 Hybrid Deploy Check: Username or Password Invalid - https://rnemeth90.github.io/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ + http://localhost:1313/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ Tue, 07 Nov 2017 13:30:00 +0000 - - https://rnemeth90.github.io/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ - <p>These days, it seems every Microsoft product comes with its own unique set of head scratchers. Microsoft Exchange Server is no exception to this. I was installing Exchange 2016 earlier today, to be used as a hybrid configuration server for Office 365 (no local mailboxes). I downloaded the self depackaging executable from Microsoft, and attempted to install it. If you currently have a hybrid configuration (which we did, with Exchange 2010), the Exchange 2016 installer will detect this and run some tests to verify that the Office 365 tenant is ready for Exchange 2016 (more info here: <a href="https://technet.microsoft.com/en-us/library/ms.exch.setup.hybridconfigurationstatuspage(v=exchg.160).aspx">https://technet.microsoft.com/en-us/library/ms.exch.setup.hybridconfigurationstatuspage(v=exchg.160).aspx</a>). You’ll be prompted for Office 365 credentials (the user must have the Organization Management role). Seems simple enough, right? Wrong.</p> -<p>After typing in the username and <em>pasting</em> the password into the password field, setup came back with an error message stating the username or password was wrong. I then clicked the back button, and it crashed. I ran through this process a few more times, all with the same outcome. I even rebooted the server, which (in my opinion) should never be the resolution to a software problem. I looked through setup logs and found no indication of what the problem could be…</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2017/11/2017-11-07_12h57_08.png" alt=""></p> -<p>It was on the fourth try that I typed in the password, and this seemed to work. I didn’t receive any error messages about the credentials being wrong. The Exchange setup seemed to continue on successfully. However, it then failed with a different error:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2017/11/2017-11-07_13h12_02.png" alt=""></p> -<p>I again looked through the setup logs and found that this error happened anytime setup tried to run the “Get-OrganizationConfig” cmdlet. After troubleshooting for a little while, and no resolution in sight, I turned to Google. One of the posts I came across said that this is a bug in the Exchange installer, and to try and use the Cumulative Update installer instead. Apparently, with Exchange 2016, the Cumulative Update installer’s include all of the Exchange binaries, not just the updated binaries. I downloaded the installer for CU7 (all 6 gigabytes of it…) and successfully installed Exchange 2016. Hope this helps anyone out there struggling with this.</p> - - - + http://localhost:1313/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ + These days, it seems every Microsoft product comes with its own unique set of head scratchers. Microsoft Exchange Server is no exception to this. I was installing Exchange 2016 earlier today, to be used as a hybrid configuration server for Office 365 (no local mailboxes). I downloaded the self depackaging executable from Microsoft, and attempted to install it. If you currently have a hybrid configuration (which we did, with Exchange 2010), the Exchange 2016 installer will detect this and run some tests to verify that the Office 365 tenant is ready for Exchange 2016 (more info here: https://technet. + Migrate Windows Deployment Services to New Server - https://rnemeth90.github.io/posts/2017-06-27-migrate-windows-deployment-services-to-new-server/ + http://localhost:1313/posts/2017-06-27-migrate-windows-deployment-services-to-new-server/ Tue, 27 Jun 2017 09:21:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-27-migrate-windows-deployment-services-to-new-server/ - <p>We have been making a great effort to move all of our internal services to Windows Server 2016. This past week, it was WDS’ turn to get migrated. Migrating this role is extremely simple. Here are the steps that I took:</p> -<ol> -<li>Create new server and install WDS role.</li> -<li>Stop WDS Service on old server</li> -<li>Stop WDS Service on new server</li> -<li>Use my “Copy-Files” PowerShell script (Available Here: <a href="https://gallery.technet.microsoft.com/scriptcenter/Copy-Files-17cba2ae">Copy-Files.ps1</a>) to copy RemoteInstall Share to new server</li> -<li>Start WDS Service on new Server</li> -<li>Shutdown old WDS Server completely</li> -<li>Update option 66/67 in DHCP scopes to reflect new WDS Server</li> -<li>Update any appropriate DNS records</li> -</ol> -<p>Note:</p> -<p>If you are unable to start the WDS service, delete the WDS database and logs from the old server located at &lt;drive letter&gt;:RemoteInstallStoresMetadata*.*. You should be able to start the service after deleting these files.</p> -<p>Simple enough! 🙂</p> - - - + http://localhost:1313/posts/2017-06-27-migrate-windows-deployment-services-to-new-server/ + We have been making a great effort to move all of our internal services to Windows Server 2016. This past week, it was WDS’ turn to get migrated. Migrating this role is extremely simple. Here are the steps that I took: Create new server and install WDS role. Stop WDS Service on old server Stop WDS Service on new server Use my “Copy-Files” PowerShell script (Available Here: Copy-Files.ps1) to copy RemoteInstall Share to new server Start WDS Service on new Server Shutdown old WDS Server completely Update option 66/67 in DHCP scopes to reflect new WDS Server Update any appropriate DNS records Note: + New Script: BulkAdd-SpamFilterWhitelist.ps1 - https://rnemeth90.github.io/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ + http://localhost:1313/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ Mon, 26 Jun 2017 22:16:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ - <p>This script is capable of adding a list of domains to an Exchange Online Spam Filter policy. It can be downloaded from TechNet or Github.</p> -<p><a href="https://github.com/rnemeth90/PowerShell/blob/master/BulkAdd-SpamFilterWhitelist.ps1">Github</a></p> -<p><a href="https://gallery.technet.microsoft.com/BulkAdd-SpamFilterWhitelist-2d2b596a">TechNet</a></p> - + http://localhost:1313/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ + This script is capable of adding a list of domains to an Exchange Online Spam Filter policy. It can be downloaded from TechNet or Github. Github TechNet - Windows 8 File History - https://rnemeth90.github.io/posts/2017-06-22-windows-8-file-history-windows-8-file-history/ + http://localhost:1313/posts/2017-06-22-windows-8-file-history-windows-8-file-history/ Thu, 22 Jun 2017 22:42:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-22-windows-8-file-history-windows-8-file-history/ - <p>File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. To begin using it, connect an external drive and search for File History on the Start Screen:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2014-11-15_14h19_47.png" alt=""></p> -<p>After opening File History, you will see this screen:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2014-11-15_14h20_32.png" alt=""></p> -<p>To enable File History, click the ‘Turn On’ button. You can select the drive you want to use by clicking ‘Select Drive’ on the left hand side from this same screen. The first time you enable File History, it will create a full backup of all files on your computer, except for files that you do not access (system files), and files you have chosen to exclude. From then on, it will create a versioned copy of every file that has changed since the last backup.</p> -<p>You can use a locally attached drive or a network share for File History. To choose how often File History backs up files; choose ‘Advanced Settings’. From here you can also choose how much space on the drive is used, and how long saved versions of files should be kept.</p> -<p>When the total space allocated to File History has been used, the feature will delete the oldest versions of files to make room for newer versions.</p> - - - + http://localhost:1313/posts/2017-06-22-windows-8-file-history-windows-8-file-history/ + File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. + How to Permanently Remove Office 365 Users - https://rnemeth90.github.io/posts/2017-06-20-how-to-permanently-remove-office-365-users/ + http://localhost:1313/posts/2017-06-20-how-to-permanently-remove-office-365-users/ Tue, 20 Jun 2017 18:13:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-20-how-to-permanently-remove-office-365-users/ - <p>After deleting a user in Office 365, their account is moved to a ‘recycle bin’ for 30 days. This allows the user account to be easily recovered. This can often cause issues when attempting to recreate a mailbox while a hybrid configuration is in place.</p> -<p>To permanently delete the user within Office 365, first delete the user in the Office 365 Admin Portal or using Powershell. Then, connect to your Azure Active Directory environment with Powershell using the “Connect-MsolService” cmdlet.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h06_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h06_20.png" alt=""></a></p> -<p>To see a list of user accounts currently in the recycle bin, run this cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h09_47.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h09_47.png" alt=""></a></p> -<p>Then, to permanently delete all accounts in the recycle bin, run this cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h10_16.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h10_16.png" alt=""></a></p> -<p>To remove a specific user, run this cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h11_15.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h11_15.png" alt=""></a></p> - - - + http://localhost:1313/posts/2017-06-20-how-to-permanently-remove-office-365-users/ + After deleting a user in Office 365, their account is moved to a ‘recycle bin’ for 30 days. This allows the user account to be easily recovered. This can often cause issues when attempting to recreate a mailbox while a hybrid configuration is in place. To permanently delete the user within Office 365, first delete the user in the Office 365 Admin Portal or using Powershell. Then, connect to your Azure Active Directory environment with Powershell using the “Connect-MsolService” cmdlet. + Access is Denied When Attempting to Delete a Dynamic Distribution Group - https://rnemeth90.github.io/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ + http://localhost:1313/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ Mon, 12 Jun 2017 13:41:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ - <p>You may receive the error below when attempting to delete a dynamic distribution group.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-12_09h29_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-12_09h29_20.png" alt=""></a></p> -<p>To resolve this, open ADUC and show advanced features (Click View &gt; Advanced Features). Then find the object for the dynamic distribution group and open the properties window. Browse to the “Object” tab and uncheck the “Protect object from accidental deletion” box. Wait for ADDS to replicate or force replication yourself.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-12_09h34_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-12_09h34_20.png" alt=""></a></p> -<p>Go back to the ECP and you should be able to delete the group.</p> - + http://localhost:1313/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ + You may receive the error below when attempting to delete a dynamic distribution group. To resolve this, open ADUC and show advanced features (Click View &gt; Advanced Features). Then find the object for the dynamic distribution group and open the properties window. Browse to the “Object” tab and uncheck the “Protect object from accidental deletion” box. Wait for ADDS to replicate or force replication yourself. Go back to the ECP and you should be able to delete the group. - Running vSphere in VMware Workstation 12 - https://rnemeth90.github.io/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/ + http://localhost:1313/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/ Mon, 29 May 2017 01:09:00 +0000 - - https://rnemeth90.github.io/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/ - <p>In this post I’ll be walking through how to run a vSphere lab in VMware Workstation. I recently decided to obtain VCP6-DCV. Rather than driving up my electric bill like I’ve done in the past using physical servers, I’m attempting to run the entire lab on my workstation and a Synology NAS.</p> -<p>If you’ve ever installed ESXi, installing it in Workstation will be a familiar process for you. VMware tools is included in the installation disc, which makes installing ESXi in Workstation dramatically easier than it used to be. . The process is very simple, so I won’t be going through those steps here unless someone asks me to in the comments. I also will not be going through the process of installing Windows Server or configuring a domain controller/DNS/DHCP, as I am sure you have done so in the past if you are reading this.</p> -<p>So that really only leaves us with installing vCenter. Most of the blogs I found for installing vCenter in VMware Workstation 12 were not accurate, and often left me with a broken installation. The process is somewhat straight-forward when deploying from the OVA. Let’s get started.</p> -<p>First, download the OVA for vCenter here: <a href="https://my.vmware.com/web/vmware/details?productId=614&amp;downloadGroup=VC650">Download vCenter</a></p> -<p>Once the download has completed, click File &gt; Open in Workstation. Browse to the OVA, then give your new VM a name and location if necessary. Accept the EULA when prompted.</p> -<p>Be sure to read it! 😎</p> -<p>Once the OVA finishes importing, do not power on the VM! There is some customization we need to do first. Close Workstation if it is open. Browse to the location on your PC that you imported the VM to. I’m using a Windows OS, so I will use File Explorer. Open the .VMX file (use Notepad or another text editor):</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-28_21h00_04.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-28_21h00_04.png" alt=""></a></p> -<p>This is the configuration file for your virtual machine. We can use it to customize the name, IPv4/6 details, DNS domain, etc. Scroll down to the last line of text, and paste this in:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>guestinfo.cis.vmdir.password <span style="color:#f92672">=</span> “vmware!” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.addr.family <span style="color:#f92672">=</span> “ipv4” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.addr <span style="color:#f92672">=</span> “10.0.0.15” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.prefix <span style="color:#f92672">=</span> “24” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.mode <span style="color:#f92672">=</span> “static” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.dns.servers <span style="color:#f92672">=</span> “10.0.0.10” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.gateway <span style="color:#f92672">=</span> “10.0.0.1” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.root.passwd <span style="color:#f92672">=</span> “vmware!” -</span></span></code></pre></div><p>Customize the above code to your needs. You will likely need to change the IPv4 details. Save the .VMX file and close your text editor. Now you can power on the virtual machine, and vCenter will run through the installation process. The installation can take around 10-15 minute in my experience. You may see generic login screens during the installation of Photon, do not login or interrupt the installation. Once it is complete, you should see the DCUI below:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h11_00.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h11_00.png" alt=""></a></p> -<p>You should now be able to browse to the IP address or DNS name of your vCenter server. Once you complete the configuration, you can login and see the page below: -<a href="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h10_39.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h10_39.png" alt=""></a></p> -<p>In my lab I am running 3 ESXi hosts, 1 Windows Server, and one vCenter server. Plenty to study for the VCP lab.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h11_31.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h11_31.png" alt=""></a></p> -<p>Good luck and be sure to leave a comment if you have any questions!</p> - - - + http://localhost:1313/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/ + In this post I’ll be walking through how to run a vSphere lab in VMware Workstation. I recently decided to obtain VCP6-DCV. Rather than driving up my electric bill like I’ve done in the past using physical servers, I’m attempting to run the entire lab on my workstation and a Synology NAS. If you’ve ever installed ESXi, installing it in Workstation will be a familiar process for you. VMware tools is included in the installation disc, which makes installing ESXi in Workstation dramatically easier than it used to be. + WSUS: Update Files Not Downloading (Content File Download Failed) - https://rnemeth90.github.io/posts/2016-11-18-wsus-update-files-not-downloading/ + http://localhost:1313/posts/2016-11-18-wsus-update-files-not-downloading/ Fri, 18 Nov 2016 15:13:00 +0000 - - https://rnemeth90.github.io/posts/2016-11-18-wsus-update-files-not-downloading/ - <p>This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-18_10h02_21.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-18_10h02_21.png" alt=""></a></p> -<p>You may also see this event (or similar) in the Event Log.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_32.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_32.png" alt=""></a></p> -<p>This problem is caused by not specifying a valid path when assigning the WSUS content drive when first installing the role. The first time you load the WSUS console after installing the role, you will be prompted to specify the path to store Windows Update files. WSUS does not like to have its content directory be the root of a partition. For example, if I were to specify “e:” as the path for the Windows Update content, the wizard would give you an error message stating that the path is not valid. However, it doesn’t prompt you to re-enter the path if you click close. The WSUS console opens immediately after and that invalid path is where WSUS will try to store your update files. This is and has been a known bug for a while and needs to be addressed by Microsoft. Evidence of the invalid path can be found in the registry under:</p> -<p>HKLMSoftwareMicrosoftUpdate ServicesServerSetupContentDir</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_44.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_44.png" alt=""></a></p> -<p>If you come across this problem, you can change the ContentDir above to a valid path. Keep in mind that it cannot be the root of a partition. You need to specify a drive letter with a subfolder (eg: e:wsus).</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h54_54.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h54_54.png" alt=""></a></p> -<p>The other option is to reinstall the WSUS role. If you remove the role, the WID database is not removed, unless you remove that role as well (or manually delete the database). This means that when you reinstall the WSUS role, it will be able to use that same database and any clients that have contacted the WSUS server will immediately show up in the console. The same is true for update metadata. The new WSUS installation will still have the same approvals, denials, etc. as the old installation.</p> -<p>Regardless of what option you choose, I suggest rebooting the server after you make the changes.</p> - - - + http://localhost:1313/posts/2016-11-18-wsus-update-files-not-downloading/ + This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates: You may also see this event (or similar) in the Event Log. This problem is caused by not specifying a valid path when assigning the WSUS content drive when first installing the role. The first time you load the WSUS console after installing the role, you will be prompted to specify the path to store Windows Update files. + WSUS: An error occurred trying to connect the WSUS server - https://rnemeth90.github.io/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ + http://localhost:1313/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ Thu, 10 Nov 2016 15:18:00 +0000 - - https://rnemeth90.github.io/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ - <p>Ran into this error message when configuring a new WSUS server:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h56_00.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h56_00.png" alt=""></a></p> -<p>Restarted the WSUS, WID, and IIS services to no avail. I even rebooted the server. The WSUS console would work for a short period of time, and then would randomly stop working.</p> -<p>I found that the WSUS app pool in IIS was being disabled anytime new clients connected to the server. I believe this was because the app pool was running out of usable memory.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h28_56.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h28_56.png" alt=""></a></p> -<p>You can manually start the app pool in IIS, but it will continue to crash.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h56_48.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h56_48.png" alt=""></a></p> -<p>The solution for me was to increase the memory limit available for the application pool:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h57_38.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h57_38.png" alt=""></a></p> -<p>By default it is only configured to use just under 2 GBs. I reconfigured it to use up to 4 GB and the WSUS console has not crashed since. After re-configuring the memory for the application pool, run an IIS reset or reboot the server.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h31_40.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h31_40.png" alt=""></a></p> -<p>UPDATE: Setting the Private Memory Limit to “0” will allow the application pool to use whatever amount of memory it needs.</p> - - - + http://localhost:1313/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ + Ran into this error message when configuring a new WSUS server: Restarted the WSUS, WID, and IIS services to no avail. I even rebooted the server. The WSUS console would work for a short period of time, and then would randomly stop working. I found that the WSUS app pool in IIS was being disabled anytime new clients connected to the server. I believe this was because the app pool was running out of usable memory. + WDS Service: The Service did not respond in a timely fashion - https://rnemeth90.github.io/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ + http://localhost:1313/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ Thu, 10 Nov 2016 02:19:00 +0000 - - https://rnemeth90.github.io/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ - <p>This was a new one for me. Usually WDS is rock solid and it just works.</p> -<p>Anyway, I was getting ready to deploy some servers in my lab and found that I couldn’t get WDS to start on my deployment server. I got this error message when trying to start the service:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h02_29.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h02_29.png" alt=""></a></p> -<p>I then tried to start the service from the Services console and got this error message:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h02_42.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h02_42.png" alt=""></a></p> -<p>“This was just working yesterday”, I said to myself. What could possibly have happened since yesterday evening that could cause this? I looked in the event log and after scrolling through the Administrative Events, I found this:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h04_33.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h04_33.png" alt=""></a></p> -<p>The solution was so obvious it was staring me in the face, but I wanted to verify first. So I fired up a cmd prompt and ran netstat, and found this:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h06_14.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h06_14.png" alt=""></a></p> -<p>I had installed DHCP on this server the night before and totally forgot about it. Anyway, the solution was simple. I just needed to tell the WDS service to not listen on port 67. To do that, just open the WDS server properties and got to the “DHCP” tab. Then check the box next to “Do not listen on DHCP Ports”.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h08_04.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h08_04.png" alt=""></a></p> -<p>I was then able to start the DHCP service.</p> - - - + http://localhost:1313/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ + This was a new one for me. Usually WDS is rock solid and it just works. Anyway, I was getting ready to deploy some servers in my lab and found that I couldn’t get WDS to start on my deployment server. I got this error message when trying to start the service: I then tried to start the service from the Services console and got this error message: “This was just working yesterday”, I said to myself. + Script to Move All Disabled AD Objects to a Specified OU - https://rnemeth90.github.io/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ + http://localhost:1313/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ Thu, 06 Oct 2016 03:03:00 +0000 - - https://rnemeth90.github.io/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ - <p>The title says it all. This script will move all disabled AD objects to a specified OU. This script accepts parameters that will allow you to specify whether you want to move Users or Computers and the destination OU. It also accepts a “test mode” parameter that will run the script and output the results, without actually modifying Active Directory.</p> -<p>This is revision 1 of the script. There are still several improvements I would like to make, including better error handling and recovery.</p> -<p>If you have any suggestions or requests, please leave a comment.</p> -<p><a href="https://drive.google.com/open?id=0B2K6VOnt6zeXMVFleWZISHZBTnc">Download Here</a></p> - + http://localhost:1313/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ + The title says it all. This script will move all disabled AD objects to a specified OU. This script accepts parameters that will allow you to specify whether you want to move Users or Computers and the destination OU. It also accepts a “test mode” parameter that will run the script and output the results, without actually modifying Active Directory. This is revision 1 of the script. There are still several improvements I would like to make, including better error handling and recovery. - Exchange 2013: Error 0x80070070 While Adding DAG Member - https://rnemeth90.github.io/posts/2016-10-04-exchange-2013-error-0x80070070-while/ + http://localhost:1313/posts/2016-10-04-exchange-2013-error-0x80070070-while/ Tue, 04 Oct 2016 00:21:00 +0000 - - https://rnemeth90.github.io/posts/2016-10-04-exchange-2013-error-0x80070070-while/ - <p>Error: A server-side database availability group administrative operation failed. Error Failed to add or remove the Failover-Clustering feature. Error: The request to add or remove features on the specified server failed. A DISM session could not be opened. An error occurred accessing the temporary folder C:WindowsTEMP57ACE2DE-4CD2-4F5F-B7A0-93D867A89A12. Ensure that the path to the temporary folder exists and that you have Read/Write permissions on the folder. Error: 0x80070070</p> -<p>Solution: I was attempting to remotely add the DAG member from the ECP on my workstation. I logged into the server and found that the system drive was nearly full (~100MB free). Luckily this mailbox server was a virtual machine, and I was able to quickly expand the drive using VMM. After doing this I was able to successfully add the mailbox server to the DAG.</p> - + http://localhost:1313/posts/2016-10-04-exchange-2013-error-0x80070070-while/ + Error: A server-side database availability group administrative operation failed. Error Failed to add or remove the Failover-Clustering feature. Error: The request to add or remove features on the specified server failed. A DISM session could not be opened. An error occurred accessing the temporary folder C:WindowsTEMP57ACE2DE-4CD2-4F5F-B7A0-93D867A89A12. Ensure that the path to the temporary folder exists and that you have Read/Write permissions on the folder. Error: 0x80070070 Solution: I was attempting to remotely add the DAG member from the ECP on my workstation. - Script for Setting the License for Multiple Office 365 User Accounts - https://rnemeth90.github.io/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ + http://localhost:1313/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ Mon, 11 Apr 2016 01:25:00 +0000 - - https://rnemeth90.github.io/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ - <p>A script for setting the Office 365 license for multiple users. Requires a CSV file named users.csv. This file must in the same directory as the script. The CSV file must contain three columns. The title of the columns should be UPN, UsageLocation, and SKU.</p> -<p><a href="https://drive.google.com/open?id=0B2K6VOnt6zeXZ2Z6OFZhZVoyenc">BulkSet-MsolUserLicense.ps1</a></p> - + http://localhost:1313/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ + A script for setting the Office 365 license for multiple users. Requires a CSV file named users.csv. This file must in the same directory as the script. The CSV file must contain three columns. The title of the columns should be UPN, UsageLocation, and SKU. BulkSet-MsolUserLicense.ps1 - The User Profile Service service failed the logon - https://rnemeth90.github.io/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ + http://localhost:1313/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ Wed, 30 Dec 2015 10:38:00 +0000 - - https://rnemeth90.github.io/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ - <p>One of my clients had a really strange issue the other day. He has a domain admin account in his domain and was not able to login to a server that I recently built. The server was an Exchange 2013 box, and was used in Coexistence mode to migrate his company from an Exchange 2007 box.</p> -<p>He was getting this error message when attempting to login:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/12/2015-12-30_09h38_53.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/12/2015-12-30_09h38_53.png" alt=""></a></p> -<p>This is a classic error message that I’m sure most technicians have seen before. Usually the resolution is to go into the registry and rename the user profile key to have a “.bak” extension and then do some other magic. However, this time, that was not the case. I looked in the registry and didn’t even see a reg key for his profile. I then looked in the c:users folder and didn’t see a folder for his profile. Strange…</p> -<p>So what exactly was happening? Well, I took a look at the Event Viewer and found this error message:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/12/2015-12-30_09h34_06.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/12/2015-12-30_09h34_06.png" alt=""></a></p> -<p>I browsed to the file referenced in the error message and deleted it. Walla! He was able to login with his admin account. I’m not sure why this file was in the default user profile. It has something to do with Customer Experience Improvement Program:</p> -<p><a href="http://www.nextofwindows.com/what-is-sqmdata-and-sqm-file-in-windows-7-and-how-to-delete-them">http://www.nextofwindows.com/what-is-sqmdata-and-sqm-file-in-windows-7-and-how-to-delete-them</a></p> - - - + http://localhost:1313/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ + One of my clients had a really strange issue the other day. He has a domain admin account in his domain and was not able to login to a server that I recently built. The server was an Exchange 2013 box, and was used in Coexistence mode to migrate his company from an Exchange 2007 box. He was getting this error message when attempting to login: This is a classic error message that I’m sure most technicians have seen before. + Azure AD Connect Password Sync &#8211; Disabled and Grayed Out - https://rnemeth90.github.io/posts/2015-10-15-azure-ad-connect-password-sync-disabled/ + http://localhost:1313/posts/2015-10-15-azure-ad-connect-password-sync-disabled/ Thu, 15 Oct 2015 10:18:00 +0000 - - https://rnemeth90.github.io/posts/2015-10-15-azure-ad-connect-password-sync-disabled/ - <p>Ran into a problem earlier with the new Azure AD Connect Wizard. We had configured the wizard and synced around 500 AD accounts. However, password sync was not working. I opened the wizard to confirm the configuration and found that “Password Hash Synchronization” was disabled. It was greyed out and could not be enabled.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_08h43_18.jpg"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_08h43_18.jpg" alt=""></a></p> -<p>I called Microsoft and worked for a couple hours with a technician to resolve the issue. Thought I should post the resolution here in case anyone else encounters this.</p> -<p>You can enable password sync by running the following script:</p> -<p>Import-Module ADSync</p> -<p>$adConnector = “&lt;Local AD Connector Name&gt;”</p> -<p>$aadConnector = “&lt;Azure AD Connector Name&gt;”</p> -<p>Set-ADSyncAADPasswordSyncState -ConnectorName $aadConnector –Enable $true</p> -<p>Set-ADSyncAADPasswordSyncConfiguration -SourceConnector $adConnector -TargetConnector $aadConnector -Enable $true</p> -<p>get-ADSyncAADPasswordSyncConfiguration -sourceconnector $adConnector</p> -<p>You need to set the value of the $adConnector and $aadConnector variables with the names of your Connectors found in the MIISClient.</p> -<p>Open the MIISClient by browsing to:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_09h39_42.jpg"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_09h39_42.jpg" alt=""></a></p> -<p>Right click on MIISClient.exe and click “Run As Administrator”.</p> -<p>You can obtain the names of your connectors in by going to the Connectors tab and looking at the Names column. There are two values here that you need to pay attention to. The Windows Azure Active Directory connector is your Azure Connector (obviously), and the other connector is your on-prem connector.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_09h39_31.jpg"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_09h39_31.jpg" alt=""></a></p> -<p>Now that you have the names, just plug them into the script and run it. You can go back to the Azure AD Connect Wizard and verify that password sync is enabled. You can also go to the Event Viewer -&gt; Application log and look for events 576 and 577. These two events are related to password sync and should show you all AD accounts that have successfully synced passwords.</p> -<p>You can force a sync by going to this location and running “DirectorySyncClientCmd.exe”.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_10h21_12.jpg"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_10h21_12.jpg" alt=""></a></p> - - - + http://localhost:1313/posts/2015-10-15-azure-ad-connect-password-sync-disabled/ + Ran into a problem earlier with the new Azure AD Connect Wizard. We had configured the wizard and synced around 500 AD accounts. However, password sync was not working. I opened the wizard to confirm the configuration and found that “Password Hash Synchronization” was disabled. It was greyed out and could not be enabled. I called Microsoft and worked for a couple hours with a technician to resolve the issue. Thought I should post the resolution here in case anyone else encounters this. + Finding All Mailboxes with a Forwarding Address in Exchange 2003 - https://rnemeth90.github.io/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ + http://localhost:1313/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ Mon, 07 Sep 2015 23:13:00 +0000 - - https://rnemeth90.github.io/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ - <p>Believe it or not, the MSP I work for still has a client who is using Exchange 2003 as their primary email service. Despite several attempts at convincing them of the power of Office 365, they refuse to migrate. Last week the CFO contacted me and requested we provide them with a report of all users who have their email forwarded to another mailbox. “Ok, no problem.” I said helpfully as the client informed me of their request (at the time I didn’t even think about them having Exchange 2003…). I figured I would just connect to their server and do some quick PowerShell magic, and that would be it. Quick and painless, right? Wrong.</p> -<p>I did the RDP dance and got connected to their server, and my jaw just about hit the floor when I couldn’t find the Exchange Management Shell! I asked around the office to see if any of the other guys could help, but no one knew what to do. However, after talking with one of the guys, I remembered that this is Active Directory we are dealing with. There are objects, and those objects have attributes. The mailboxes/user accounts are objects, and those objects have attributes. So what attribute is it that controls forwarding addresses? I manually found one of the users who had a forwarding address configured. Then I opened up Active Directory Users and Computers, opened up her account properties, and went to the Attribute Editor tab. I filtered for attributes that have values and was able to see the email address that her mail was forwarding to. This was the “altRecipient” attribute.</p> -<p>I then did an “Advanced” search in Active Directory Users and Computers for any objects that have the “altRecipient” attribute configured, like so:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/09/ExchangeForwarding.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/09/ExchangeForwarding.png" alt=""></a></p> -<p>This search showed me all of the mailboxes that have an alternate recipient (forwarding address) configured. Not sure if there is another way to obtain this information, but this is the way that worked for me. Hopefully this article is able to help someone in the same situation.</p> - + http://localhost:1313/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ + Believe it or not, the MSP I work for still has a client who is using Exchange 2003 as their primary email service. Despite several attempts at convincing them of the power of Office 365, they refuse to migrate. Last week the CFO contacted me and requested we provide them with a report of all users who have their email forwarded to another mailbox. “Ok, no problem.” I said helpfully as the client informed me of their request (at the time I didn’t even think about them having Exchange 2003…). - Script for Querying All AD Computers Time Source - https://rnemeth90.github.io/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ + http://localhost:1313/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ Tue, 01 Sep 2015 21:05:00 +0000 - - https://rnemeth90.github.io/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ - <p>This script will iterate through all computers in Active Directory and return the configured time server for each computer.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span><span style="color:#75715e">&lt;# -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">SYNOPSIS</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Get time source for all computers in domain -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">EXAMPLE</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Get-TimeSource -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">NOTES</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Author: Ryan Nemeth - RyanNemeth@live.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Site: http://www.geekyryan.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">LINK</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> http://www.geekyryan.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">DESCRIPTION</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> This function will iterate through all computers/servers in a domain and return the time source -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> for each. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#&gt;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Write-Host -foregroundcolor Red -BackgroundColor black <span style="color:#e6db74">&#34;This script must be run on a domain controller and requires that the AD Powershell module be installed&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$module = Get-Module -ListAvailable | Select-Object -ExpandProperty Name -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span>($module <span style="color:#f92672">-notcontains</span> <span style="color:#e6db74">&#34;ActiveDirectory&#34;</span>) { -</span></span><span style="display:flex;"><span> Write-Host -foregroundcolor red -backgroundcolor black <span style="color:#e6db74">&#34;***Active Directory Powershell Module Not Found***&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span> { -</span></span><span style="display:flex;"><span> Write-Host -foregroundcolor yellow <span style="color:#e6db74">&#34;Found Active Directory Powershell Module. Importing...&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Import-Module ActiveDirectory -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$computers = get-adcomputer -filter * | Select-Object -ExpandProperty Name -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span>($computer <span style="color:#66d9ef">in</span> $computers) { -</span></span><span style="display:flex;"><span> $tm_source = w32tm /query /computer<span style="color:#960050;background-color:#1e0010">:</span>$computer /source -</span></span><span style="display:flex;"><span> write-host <span style="color:#e6db74">&#34;The time source for&#34;</span> $computer <span style="color:#e6db74">&#34;is&#34;</span> $tm_source -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><img src="https://github.com/rnemeth90/PowerShell/blob/master/NTP/Get-TimeSource.ps1" alt=""></p> - - - + http://localhost:1313/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ + This script will iterate through all computers in Active Directory and return the configured time server for each computer. &lt;# .SYNOPSIS Get time source for all computers in domain .EXAMPLE Get-TimeSource .NOTES Author: Ryan Nemeth - RyanNemeth@live.com Site: http://www.geekyryan.com .LINK http://www.geekyryan.com .DESCRIPTION This function will iterate through all computers/servers in a domain and return the time source for each. #&gt; Write-Host -foregroundcolor Red -BackgroundColor black &#34;This script must be run on a domain controller and requires that the AD Powershell module be installed&#34; $module = Get-Module -ListAvailable | Select-Object -ExpandProperty Name if($module -notcontains &#34;ActiveDirectory&#34;) { Write-Host -foregroundcolor red -backgroundcolor black &#34;***Active Directory Powershell Module Not Found***&#34; } else { Write-Host -foregroundcolor yellow &#34;Found Active Directory Powershell Module. + Error When Reinstalling DirSync - https://rnemeth90.github.io/posts/2015-08-13-error-when-reinstalling-dirsync/ + http://localhost:1313/posts/2015-08-13-error-when-reinstalling-dirsync/ Thu, 13 Aug 2015 18:59:00 +0000 - - https://rnemeth90.github.io/posts/2015-08-13-error-when-reinstalling-dirsync/ - <p>Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process:</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2015/08/1.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/1.png" alt=""></a></p> -<p>I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do:</p> -<ul> -<li>Uninstall Windows Azure Active Directory Sync tool and reboot -<a href="https://geekyryan.com/wp-content/uploads/2015/08/2.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/2.png" alt=""></a></li> -</ul> -<p>Remove this directory and all subfolders: C:Program FilesWindows Azure Active Directory Sync -<a href="https://geekyryan.com/wp-content/uploads/2015/08/3.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/3.png" alt=""></a></p> -<p>If you created a domain account to use for DirSync, remove it. Also remove the Office 365 account you created.</p> -<ul> -<li>Delete the Group accounts that the DirSync wizard created. Their names all begin with “FIM”</li> -</ul> -<p><a href="https://geekyryan.com/wp-content/uploads/2015/08/4.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/4.png" alt=""></a></p> -<p>Uninstall MSSQL:</p> -<ul> -<li>Delete the MSSQL directory: C:Program FilesMicrosoft SQL Server</li> -<li>Reboot!</li> -<li>You should be able to install and configure DirSync now.</li> -</ul> -<p><a href="https://geekyryan.com/wp-content/uploads/2015/08/5.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/5.png" alt=""></a></p> - - - + http://localhost:1313/posts/2015-08-13-error-when-reinstalling-dirsync/ + Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process: I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do: + Failed to Mount Exchange 2010 Database - https://rnemeth90.github.io/posts/2015-08-12-failed-to-mount-exchange-2010-database/ + http://localhost:1313/posts/2015-08-12-failed-to-mount-exchange-2010-database/ Wed, 12 Aug 2015 12:59:00 +0000 - - https://rnemeth90.github.io/posts/2015-08-12-failed-to-mount-exchange-2010-database/ - <p>Recently, one of my users’ came to me and said he was missing two months worth of email. This was just after migrating to Exchange Online. We were using Exchange 2010 with System Center DPM for backups.</p> -<p>I restored the database that the users’ mailbox was on from a backup then copied it over to the Exchange server from the network share I restored it to. All was going well, until I tried to mount the darn thing.</p> -<p>I was getting this error and could not for the life of me decry-pt the meaning of it. There is obviously some type of IO issue/file not found. But what could it be?</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/1-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/1-1.png" alt=""></a></p> -<p>I figured I’d better kick this one off with some basic troubleshooting. First, I checked the health of the database and made sure it was clean. Passed that test…</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/2-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/2-1.png" alt=""></a></p> -<p>Then ran a repair on the database, to no avail.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/3-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/3-1.png" alt=""></a></p> -<p>After racking my brain for a good thirty minutes, and a few failed Google searches, I found the solution. It was so simple! I created the log file directory in the folder with the database, and voila, the database mounted without a single error!</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/7.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/7.png" alt=""></a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/4-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/4-1.png" alt=""></a><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/5-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/5-1.png" alt=""></a></p> -<p>I was able to see the ‘supposed’ location of the log file by opening the Exchange Management Shell and running the ‘Get-MailboxDatabase’ cmdlet, like so:</p> -<p><em>Get-MailBoxDatabase –Identity <Recovery DB Name> | FL Name, ServerName, EDBFilePath, LogFolderPath</em></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/6.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/6.png" alt=""></a></p> -<p>I’m not sure why the database mounting process isn’t capable of creating the log file directory… I think Microsoft would have thought and planned for a situation like this. Hope this helps!</p> - - - + http://localhost:1313/posts/2015-08-12-failed-to-mount-exchange-2010-database/ + Recently, one of my users’ came to me and said he was missing two months worth of email. This was just after migrating to Exchange Online. We were using Exchange 2010 with System Center DPM for backups. I restored the database that the users’ mailbox was on from a backup then copied it over to the Exchange server from the network share I restored it to. All was going well, until I tried to mount the darn thing. + Ping Sweeping with FPing - https://rnemeth90.github.io/posts/2015-03-09-ping-sweeping-with-fping/ + http://localhost:1313/posts/2015-03-09-ping-sweeping-with-fping/ Mon, 09 Mar 2015 01:08:00 +0000 - - https://rnemeth90.github.io/posts/2015-03-09-ping-sweeping-with-fping/ - <p>I generally use NMAP for any type of host discovery, but recently started experimenting with FPing. One thing I found is that, when performing a ping sweep, not only do I see the hosts that replied to the ping, but FPing also sends any unreachable IP addresses to stdout (which is super annoying and ugly if you ask me…).</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h04_50.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h04_50.png" alt=""></a></p> -<p>Anyway, after a bit of research, I found a nifty way to suppress these messages. Linux allows us to redirect all error messages to /dev/null. So instead of just running the vanilla fping -a -g…. you would run the program and output all error messages /dev/null, like so:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h07_14.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h07_14.png" alt=""></a></p> - + http://localhost:1313/posts/2015-03-09-ping-sweeping-with-fping/ + I generally use NMAP for any type of host discovery, but recently started experimenting with FPing. One thing I found is that, when performing a ping sweep, not only do I see the hosts that replied to the ping, but FPing also sends any unreachable IP addresses to stdout (which is super annoying and ugly if you ask me…). Anyway, after a bit of research, I found a nifty way to suppress these messages. - Powershell: SID to Username - https://rnemeth90.github.io/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ + http://localhost:1313/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ Mon, 08 Dec 2014 13:43:00 +0000 - - https://rnemeth90.github.io/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ - <p>This is a simple script to convert a SID to a username</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span><span style="color:#75715e"># Returns a username based on a SID</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Author: Ryan Nemeth</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Date: 12/2/2014</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$SID = read-host <span style="color:#960050;background-color:#1e0010">“</span>Please enter the SID<span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#960050;background-color:#1e0010">”</span> -</span></span><span style="display:flex;"><span>$object = New-Object System.Security.Principal.SecurityIdentifier($SID) -</span></span><span style="display:flex;"><span>$User = $object.Translate( \[System.Security.Principal.NTAccount\]) -</span></span><span style="display:flex;"><span>write-host <span style="color:#960050;background-color:#1e0010">“</span>The user is<span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#960050;background-color:#1e0010">”</span> $User.Value -</span></span></code></pre></div> - - + http://localhost:1313/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ + This is a simple script to convert a SID to a username # Returns a username based on a SID # Author: Ryan Nemeth # Date: 12/2/2014 $SID = read-host “Please enter the SID: ” $object = New-Object System.Security.Principal.SecurityIdentifier($SID) $User = $object.Translate( \[System.Security.Principal.NTAccount\]) write-host “The user is: ” $User.Value + DHCP Address Negotiation Process - https://rnemeth90.github.io/posts/2014-12-08-dhcp-address-negotiation-process/ + http://localhost:1313/posts/2014-12-08-dhcp-address-negotiation-process/ Mon, 08 Dec 2014 03:08:00 +0000 - - https://rnemeth90.github.io/posts/2014-12-08-dhcp-address-negotiation-process/ - <p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/12/2014-12-07_22h07_33.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/12/2014-12-07_22h07_33.png" alt=""></a></p> - + http://localhost:1313/posts/2014-12-08-dhcp-address-negotiation-process/ + - Unlock a Domain User from CMD Line - https://rnemeth90.github.io/posts/2014-12-08-unlock-domain-user-from-cmd-line/ + http://localhost:1313/posts/2014-12-08-unlock-domain-user-from-cmd-line/ Mon, 08 Dec 2014 02:11:00 +0000 - - https://rnemeth90.github.io/posts/2014-12-08-unlock-domain-user-from-cmd-line/ - <p>To unlock a domain user from the command line, use this command:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>net user &amp;lt;username&amp;gt; /domain /active:yes -</span></span></code></pre></div><p>This can also be done using Powershell:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Unlock-ADAccount -identity <span style="color:#960050;background-color:#1e0010">“</span>CN=John,OU=myUsers,DC=myDomain,DC=local<span style="color:#960050;background-color:#1e0010">”</span> -</span></span></code></pre></div> + http://localhost:1313/posts/2014-12-08-unlock-domain-user-from-cmd-line/ + To unlock a domain user from the command line, use this command: net user &amp;lt;username&amp;gt; /domain /active:yes This can also be done using Powershell: Unlock-ADAccount -identity “CN=John,OU=myUsers,DC=myDomain,DC=local” - The Case of Transitive Trusts and Dropped RPC Connections - https://rnemeth90.github.io/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ + http://localhost:1313/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ Tue, 25 Nov 2014 01:27:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ - <p>I was at a client earlier this morning, working to get a transitive forest trust setup between their two domains. Setting up the trust on ServerA to DomainB went without issue. However, when trying to create the trust between ServerB and DomainA, I received this error: The secure channel reset on Active Directory Domain Controller (Your domain controller) of domain (Your domain) to domain (your other domain) failed with error: RPC server is unavailable.</p> -<p>Troubleshooting (as always) started off with the basics: is the firewall on or off, are the services running, are the names being properly resolved, etc. Well, the Windows Firewall on both servers was off and -the RPC services were running. So what now?? I fired up NMAP on ServerB and did a syn scan on ServerA. After reviewing the output, I could see that the ports were open. I then went over to ServerA and opened up the Services MSC console. The RPC services appeared to be running. Being that they are system services and you cannot manually interact with them, I was unable to manually restart them. Just out of curiosity,</p> -<p>I opened a command prompt while connected to that server and ran Netstat -A. This is when I had the “AHA!” moment. Nothing was listening on any of the RPC ports! I rebooted the server (something I don’t really like to do..), logged in and ran Netstat -A again. This time, RPC was listening. I went back over to ServerB, walked through the New Trust Wizard, and success! Oh, the feeling of victory!</p> - + http://localhost:1313/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ + I was at a client earlier this morning, working to get a transitive forest trust setup between their two domains. Setting up the trust on ServerA to DomainB went without issue. However, when trying to create the trust between ServerB and DomainA, I received this error: The secure channel reset on Active Directory Domain Controller (Your domain controller) of domain (Your domain) to domain (your other domain) failed with error: RPC server is unavailable. - Creating Applocker Policies - https://rnemeth90.github.io/posts/2014-11-17-creating-applocker-policies/ + http://localhost:1313/posts/2014-11-17-creating-applocker-policies/ Mon, 17 Nov 2014 01:40:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-17-creating-applocker-policies/ - <p>Application Control Policies can be used to restrict what programs a user is allowed to run. They can be created at the local Group Policy level or the Domain GPO level. There are 4 different types of Applocker RULES that you can implement, depending on what type of executable you want to control access to.</p> -<p>Executable Rules – EXE’s, COM’s, etc.</p> -<p>Script Rules – batch files, VB scripts, etc.</p> -<p>AppX Rules – AppX Packages (Windows 8.1/Server 2012 R2 Metro Interface programs)</p> -<p>Windows Installer Rules – Windows Installer Packages and MSU Packages</p> -<p>After choosing what type of executable file you want to control, you can choose the corresponding rule type. Then, you will be able to choose the criteria for that rule type. Applocker rule criteria are things such as file path, publisher, and file hash. Criteria allow you to be more granular with your selections. Rather than saying you want to block access to ALL executable’s on a computer, you can choose to block access to executable’s published by a certain vendor, or found in a specified directory.</p> -<p>Applocker can be found in the Group Policy Editor at: Computer Configuration\Windows Settings\Security Settings. Application Control Policies. By right-clicking on the Applocker node, you can configure rule enforcement. You have the option to enforce rules or audit rules based on rule type. Auditing will allow</p> -<p>you get a good grasp on what Applocker will do in your environment if you are unsure.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h18_31.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h18_31.png" alt=""></a></p> -<p>Clicking the Advanced tab of this window will allow you to configure rule enforcement for Dynamic Link Libraries. It’s best to leave DLL rule enforcement disabled, because it can cause a system to suffer dramatic performance hits.</p> -<p>Underneath the Applocker node, you will find nodes for the 4 different rule types. You can create new rules by right clicking on any of these nodes and clicking “Create New Rule”. Before creating any rules, I advise you to create the default rules. Doing this will ensure that users are still able to run programs in the Program Files directory and the Windows directory. Also, members of the built-in Administrators group will be allowed to run ANY files.</p> -<p>When creating custom Applocker rules, you can choose to allow or deny the program, and what group the rule will apply to (by default, the “Everyone” special identity is always selected).</p> -<p>You will also be able to choose the criteria for the executable that you are controlling.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h26_30.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h26_30.png" alt=""></a></p> -<p>If the executable has a digital signature from the software publisher, choose “Publisher”. Doing so will give you even more options:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h28_47.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h28_47.png" alt=""></a></p> -<p>This allows you to really drill down and get granular with the rule. Microsoft allows us to control access to the file based on the Publisher, the Product Name, the File Name, and even the File Version.</p> -<p>Creating rules based on File Path criteria is not advised, being that if the file jumps directories, the rule will no longer apply. I also don’t advise using the File Hash criteria. My reason behind this is, if the file gets updated, the hash changes. If that happens, the rule is no longer valid.</p> -<p>After choosing the criteria type you would like to use, you can choose to create exceptions, if any. When multiple rules conflict, the order of precedence is Publisher, File Hash, and then File Path. So Publisher rules will always override File Hash rules, File Hash rules will always override File Path rules, and you get the point…</p> -<p>Finally, in order for your endpoint workstations to process Applocker rules, the Application Identity Service must be running. I like to control this with the same GPO that I configure Applocker in.</p> - - - + http://localhost:1313/posts/2014-11-17-creating-applocker-policies/ + Application Control Policies can be used to restrict what programs a user is allowed to run. They can be created at the local Group Policy level or the Domain GPO level. There are 4 different types of Applocker RULES that you can implement, depending on what type of executable you want to control access to. Executable Rules – EXE’s, COM’s, etc. Script Rules – batch files, VB scripts, etc. AppX Rules – AppX Packages (Windows 8. + TCP/IP Network Fundamentals - https://rnemeth90.github.io/posts/2014-11-16-tcpip-network-fundamentals/ + http://localhost:1313/posts/2014-11-16-tcpip-network-fundamentals/ Sun, 16 Nov 2014 21:20:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-16-tcpip-network-fundamentals/ - <p>Going over the basics of network fundamentals and all the models and ideas behind them. The most pushed idea is the OSI networking model which consists of 7 layers, all of which deal with a certain aspect of the networking model.</p> -<p>A P S T N D P</p> -<p>From the top down this represents the following</p> -<p>Layer 7: Application – This layer is the channel between software and external requests. For example, a web server would work with this layer to process HTTP requests.</p> -<p>Layer 6: Presentation – This layer organizes data formats such as JPEG, Text, ASCII, etc</p> -<p>Layer 5: Session – This layer deals with session control; How a conversation should start, function, and end. It can be considered the broken between the layer below and the layers above. It will ensure all the data is proper when being passed up or down.</p> -<p>Layer 4: Transport – This layer is solely focused on data delivery. It deals with many protocols, but most notably it deals with TCP and UDP packets, any checksum errors, and error recovery</p> -<p>Layer 3: Network – This layer deals with logical addressing and routing. It deals with the actual delivery of packets across multiple networks.</p> -<p>Layer 2: Data Link – This layer deals with the rules of how data can be transmitted over a wire such as CSMA/CD and the like. It also deals with encapsulating frames to be transported over a local network</p> -<p>Layer 1: Physical – The actual hardware and electrical signaling to move data over the network. Network cards, cabling, and other hardware are part of this layer</p> -<p>Generic overview of the OSI model above lets work on the idea of some older and modern networks.</p> -<p>Hubs – Devices that simply take a signal and regenerate it out of all ports that are connected.</p> -<p>Switches – Devices that take a signal and make some sort of smart decision to provide a single path from one port to another</p> -<p>Routers – Devices that make decisions based upon higher level information (logical addressing) and will make intelligent decisions on how to handle that data, both incoming and outgoing. Segments networks into two different ones.</p> -<p>Bridge – A device that segments a network in two.</p> -<p>Collision Domain – The bounds where a collision may occur. This is relevant for networks utilizing half-duplex communication and for older devices such as hubs.</p> -<p>Broadcast Domain – The bounds where a broadcast can reach.</p> -<p>Collision Domains: Forgive the visio art, it will get better… hopefully</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h18_36.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h18_36.png" alt=""></a></p> -<p><a href="http://xenodez.pleasedonthack.us/?attachment_id=49">&lt;span style=&ldquo;color: windowtext; font-family: &ldquo;Verdana&rdquo;,sans-serif; font-size: 9.0pt; mso-no-proof: yes; text-decoration: none; text-underline: none;&quot;&gt;</a></p> -<p>Every computer connected to that hub is in the collision domain noted by the circle. With a hub, the signal gets sent to every device connected to it, regardless of whether it was meant to go to that machine or not. When the PC at the top left sends information at the same time as the PC on the bottom right, a collision is likely to occur</p> -<p><a href="http://xenodez.pleasedonthack.us/?attachment_id=52">&lt;span style=&ldquo;color: windowtext; font-family: &ldquo;Verdana&rdquo;,sans-serif; font-size: 9.0pt; mso-no-proof: yes; text-decoration: none; text-underline: none;&quot;&gt;</a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h18_45.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h18_45.png" alt=""></a></p> -<p>Every computer connected to this switch is limited in its collision domain to the port on the switch and the network card in the PC. The reason being that switches do not just take a signal and send it out of all the ports, it is intelligent enough to be able to send information directly to the PC it needs to. This is further mitigated by the fact that a computer connected to a switch may operate at full-duplex, allowing both simultaneous sending and receiving of information.</p> -<p>Collisions and how they are handled:</p> -<p>The way computers avoid collision in this sense is via something called CSMA/CD or Carrier Sense Multiple Access/Collision Avoidance. The way it works is this, a computer will wait until the line is silent before sending information. Every computer will listen to determine whether the line is truly clear. If two computers were to send at the same time, and a collision were to occur, the computers will immediately trigger a random back off time in which they will not try resending that information until the timer is up.</p> -<p>Unicast vs Broadcast vs Multicast</p> -<p>The idea between these concepts is fairly simple. Unicast deals with a transmission that is intended for one recipient. A broadcast is a transmission that is meant for all recipients that are able to hear it. Multicast is intended for a specific group of recipients.</p> - - - + http://localhost:1313/posts/2014-11-16-tcpip-network-fundamentals/ + Going over the basics of network fundamentals and all the models and ideas behind them. The most pushed idea is the OSI networking model which consists of 7 layers, all of which deal with a certain aspect of the networking model. A P S T N D P From the top down this represents the following Layer 7: Application – This layer is the channel between software and external requests. For example, a web server would work with this layer to process HTTP requests. + BranchCache - https://rnemeth90.github.io/posts/2014-11-16-branchcache/ + http://localhost:1313/posts/2014-11-16-branchcache/ Sun, 16 Nov 2014 21:16:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-16-branchcache/ - <p>Branchcache is a technology unique to Windows 7 and Windows Server 2008 R2. It provides faster connection to shared files across wide area networks. Branchcache works by caching content hosted on remote servers on a local caching server in the LAN. When a client queries for data on a remote server, it first looks in the local caching server. If the data is not found there, the remote server is accessed and transfer’s the data to the local caching server, where it is then accessed by the client who originally made the request. That way, all future client requests will not have to go across the wide area network, rather opting to access the local caching server until the data changes.</p> -<p>Branchcache is only available on Windows 7 clients running Enterprise or Ultimate, and Windows Server 2008 R2. Branchcache becomes active when the round trip latency time from client to remote server exceeds 80 milliseconds.</p> -<p>Branchcache is available in two modes: distributed cache mode and hosted cache mode. What you just read above was the basics of hosted cached mode. Distributed cache mode works differently to achieve the same results. When a client accesses data across the WAN, it stores that data in its own cache. This way, if another client needs access to the data, it can retrieve it locally. Also, this allows each client to host part of the cache, rather than one machine hosting the entire cache.</p> -<p>There are two steps to configuring Branchcache on a Windows 7 client. I will not include the server configuration at this point in time.</p> -<p>Enable Branchcache (Hosted or Distributed, Server 08 R2 will be required for Hosted mode)</p> -<p>Configure the appropriate ports within the Windows Firewall</p> -<p>You can enable Branchcache from within Group Policy or by using the Netsh command. When using Group Policy, navigate to Computer Configuration &gt; Administrative Templates &gt; Network &gt; Branchcache. From here you can turn on Branchcache and enable the mode you want to use. You can also set the percentage of disk space to be used for caching. After this, open the Windows Firewall and unblock the Branchcache ports. You only need to do this when configuring Branchcache via Group Policy. Using the Netsh command automatically configures the firewall. Here are the basic commands for Netsh:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>Netsh Branchcache set service mode<span style="color:#f92672">=</span>distributed -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Netsh Branchcache reset -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Netsh Branchcache show status -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Netsh Branchcache set cachesize -</span></span></code></pre></div><p>*Configuring Branchcache must be done from an administrative command prompt.</p> - - - + http://localhost:1313/posts/2014-11-16-branchcache/ + Branchcache is a technology unique to Windows 7 and Windows Server 2008 R2. It provides faster connection to shared files across wide area networks. Branchcache works by caching content hosted on remote servers on a local caching server in the LAN. When a client queries for data on a remote server, it first looks in the local caching server. If the data is not found there, the remote server is accessed and transfer’s the data to the local caching server, where it is then accessed by the client who originally made the request. + File History - https://rnemeth90.github.io/posts/2014-11-15-file-history/ + http://localhost:1313/posts/2014-11-15-file-history/ Sat, 15 Nov 2014 20:02:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-15-file-history/ - <p>File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. To begin using it, connect an external drive and search for File History on the Start Screen:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-15_14h19_47.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-15_14h19_47.png" alt=""></a></p> -<p>After opening File History, you will see this screen:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-15_14h20_32.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-15_14h20_32.png" alt=""></a></p> -<p>To enable File History, click the ‘Turn On’ button. You can select the drive you want to use by clicking ‘Select Drive’ on the left hand side from this same screen. The first time you enable File History, it will create a full backup of all files on your computer, except for files that you do not access (system files), and files you have chosen to exclude. From then on, it will create a versioned copy of every file that has changed since the last backup.</p> -<p>You can use a locally attached drive or a network share for File History. To choose how often File History backs up files; choose ‘Advanced Settings’. From here you can also choose how much space on the drive is used, and how long saved versions of files should be kept.</p> -<p>When the total space allocated to File History has been used, the feature will delete the oldest versions of files to make room for newer versions.</p> - - - + http://localhost:1313/posts/2014-11-15-file-history/ + File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. + Layer 2 Switching Fundamentals - https://rnemeth90.github.io/posts/2012-11-16-layer-2-switching-fundamentals/ + http://localhost:1313/posts/2012-11-16-layer-2-switching-fundamentals/ Fri, 16 Nov 2012 21:26:00 +0000 - - https://rnemeth90.github.io/posts/2012-11-16-layer-2-switching-fundamentals/ - <p>Switches are devices that support a large number of ports to connect devices to the network.</p> -<h3 id="design" >Design: -<span> - <a href="#design"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h3><p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h22_54.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h22_54.png" alt=""></a></p> -<p>More towards a CCNP or CCDA topic, but designing a network when it comes to the switching side can be done in three building blocks. The access layer, the distribution layer, and the core layer. The access layer generally has a high port density, can support VLANs, QoS, and access lists. The distribution layer will aggregate multiple access layer switches. These are also generally Layer 3 switches to allow routing among an enterprise. It will need to be able to handle the volume of traffic in addition to supporting the same features as the access layer switches. The core layer is the device which will need the highest bandwidth backplane to deal with all of the traffic.</p> -<h3 id="how-switches-handle-traffic" >How switches handle traffic: -<span> - <a href="#how-switches-handle-traffic"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h3><p>A switch is an intelligent device that can make some decisions on how to handle the data it is given. Switches can be divided into two categories for these decisions: Layer 2 or Layer 3 switches. For the CCNA we will only be interested in the layer 2 switches. Layer 2 switches operate at the data link layer. This layer deals primarily with MAC addresses. A Layer 2 switch will build a CAM table full of dynamically learned MAC addresses. The way it learns these addresses is by inspecting the layer 2 header/trailer and learning the source MAC addresses on the frames it receives. A frame is what a packet is encapsulated in when it moves from device to device across the network.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h23_04.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h23_04.png" alt=""></a></p> -<p>With this example the switch has learned PC1/PC2/and PC3′s MAC addresses. If a packet came in on Fa0/4 from PC4, the switch would look at the source MAC address and put an entry for 4444.4444.4444 on Fa0/4. A switch will route traffic based on this table. There are a few decisions it must make to determine how to handle traffic. When it first receives a frame it will consult it’s CAM table to determine whether or not it has the source MAC address listed for that port. If not, it will add it to the CAM table. In the example above, PC1 sent a frame to the switch, the switch noticed PC1′s MAC address was not in it’s table and added it. The next thing it looks at is the destination MAC address. The CAM table is again consulted. If it finds a match the switch will send the frame directly to the recipient it needs to on whatever port it is on. In the example above, PC1 sends a frame to PC3. Because the switch sees 1111.1111.1111 sending to 3333.3333.3333 and has an entry for 3333.3333.3333 it will send the frame out of port Fa0/3 to the recipient. If a destination is not in the CAM table the switch will need to try to find the recipient. In this case the switch will decide to broadcast the frame out of every port EXCEPT the one it came in on. In this example, PC1 sends a frame destined for PC4. The switch will see a frame from 1111.1111.1111 to 4444.4444.4444. PC4′s MAC address is not in it’s table. The switch will then send the frame out of every port except for Fa0/1 (the source). When PC2 and PC3 get this frame, it will determine if the frame was meant for it, and if not it will ignore it. PC4 will also make the same decision and PC4 will respond. Once PC4 has responded the switch will be able to add PC4′s MAC address to it’s table on Fa0/4.</p> - - - + http://localhost:1313/posts/2012-11-16-layer-2-switching-fundamentals/ + Switches are devices that support a large number of ports to connect devices to the network. Design: Link to heading More towards a CCNP or CCDA topic, but designing a network when it comes to the switching side can be done in three building blocks. The access layer, the distribution layer, and the core layer. The access layer generally has a high port density, can support VLANs, QoS, and access lists. + User Account Control - https://rnemeth90.github.io/posts/2012-11-15-user-account-control-copy/ + http://localhost:1313/posts/2012-11-15-user-account-control-copy/ Thu, 15 Nov 2012 16:01:00 +0000 - - https://rnemeth90.github.io/posts/2012-11-15-user-account-control-copy/ - <p>Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system.</p> -<p>For a standard user, a token with the most basic privileges is assigned. Administrators have two tokens assigned, the first token contains all privileges usually awarded to an administrator (unrestricted), and the second is similar to that awarded to a basic user. This way, all programs that the administrator runs, including the Windows Shell, are run in basic user mode (this is why administrators still receive UAC prompts, but do not get asked for credentials). When an application requests higher privileges, the higher integrity token is used .</p> -<p>User Account Control prompts each have their own meaning based on the color (blue, grey, yellow, or red. The blue prompt (Figure 1) means that a built in Windows component that is signed by Microsoft is requesting administrative privileges to continue. This prompt has a multicolored shield in the upper left corner. The grey prompt (Figure 2) means a software application that is signed by a third party developer is requesting admin privileges. This prompt has a yellow shield with a black exclamation mark in the upper left corner. The yellow prompt (Figure 3) signifies that a unsigned executable is requesting administrator privileges. This prompt also had a yellow shield with black exclamation mark in the upper left corner, and looks somewhat generic. Finally, the red prompt (Figure 4) means a program that was specifically blocked by an administrator has attempted to run.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BBlue.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BBlue.png" alt=""></a></p> -<p>Figure 1</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BGrey.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BGrey.png" alt=""></a></p> -<p>Figure 2</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BYellow.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BYellow.png" alt=""></a></p> -<p>Figure 3</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BRED.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BRED.png" alt=""></a></p> -<p>Figure 4</p> - - - + http://localhost:1313/posts/2012-11-15-user-account-control-copy/ + Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system. + User Account Control - https://rnemeth90.github.io/posts/2012-11-15-user-account-control/ + http://localhost:1313/posts/2012-11-15-user-account-control/ Thu, 15 Nov 2012 16:01:00 +0000 - - https://rnemeth90.github.io/posts/2012-11-15-user-account-control/ - <p>Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system.</p> -<p>For a standard user, a token with the most basic privileges is assigned. Administrators have two tokens assigned, the first token contains all privileges usually awarded to an administrator (unrestricted), and the second is similar to that awarded to a basic user. This way, all programs that the administrator runs, including the Windows Shell, are run in basic user mode (this is why administrators still receive UAC prompts, but do not get asked for credentials). When an application requests higher privileges, the higher integrity token is used.</p> -<p>User Account Control prompts each have their own meaning based on the color (blue, grey, yellow, or red. The blue prompt (Figure 1) means that a built in Windows component that is signed by Microsoft is requesting administrative privileges to continue. This prompt has a multicolored shield in the upper left corner. The grey prompt (Figure 2) means a software application that is signed by a third party developer is requesting admin privileges. This prompt has a yellow shield with a black exclamation mark in the upper left corner. The yellow prompt (Figure 3) signifies that a unsigned executable is requesting administrator privileges. This prompt also had a yellow shield with black exclamation mark in the upper left corner, and looks somewhat generic. Finally, the red prompt (Figure 4) means a program that was specifically blocked by an administrator has attempted to run.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BBlue.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BBlue.png" alt=""></a></p> -<p>Figure 1</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BGrey.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BGrey.png" alt=""></a></p> -<p>Figure 2</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BYellow.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BYellow.png" alt=""></a></p> -<p>Figure 3</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BRED.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BRED.png" alt=""></a></p> -<p>Figure 4</p> - - - + http://localhost:1313/posts/2012-11-15-user-account-control/ + Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system. + diff --git a/public/posts/page/1/index.html b/public/posts/page/1/index.html index edf6d2fe..3e3304df 100644 --- a/public/posts/page/1/index.html +++ b/public/posts/page/1/index.html @@ -1 +1,10 @@ -https://rnemeth90.github.io/posts/ \ No newline at end of file + + + + http://localhost:1313/posts/ + + + + + + diff --git a/public/posts/page/2/index.html b/public/posts/page/2/index.html new file mode 100644 index 00000000..1f1053cc --- /dev/null +++ b/public/posts/page/2/index.html @@ -0,0 +1,381 @@ + + + + + + Posts · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    +
    +

    + + Posts + +

    +
    + + + + + + + + + +
      + + +
    • «
    • + + + + + + + + + + + + + + +
    • 1
    • + + + + + + + + + + + + + +
    • 2
    • + + + + + + + + + + + + + +
    • 3
    • + + + + + + + + + + + + + +
    • 4
    • + + + + + + + + + + + + + +
    • 5
    • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    • »
    • + + +
    + + +
    + +
    + +
    +
    + © + + 2012 - + + 2024 + Ryan Nemeth + · + + Powered by Hugo & Coder. + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/posts/page/3/index.html b/public/posts/page/3/index.html new file mode 100644 index 00000000..22af340d --- /dev/null +++ b/public/posts/page/3/index.html @@ -0,0 +1,381 @@ + + + + + + Posts · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    +
    +

    + + Posts + +

    +
    + + + + + + + + + +
      + + +
    • «
    • + + + + + + + + + + + + + + +
    • 1
    • + + + + + + + + + + + + + +
    • 2
    • + + + + + + + + + + + + + +
    • 3
    • + + + + + + + + + + + + + +
    • 4
    • + + + + + + + + + + + + + +
    • 5
    • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    • »
    • + + +
    + + +
    + +
    + +
    +
    + © + + 2012 - + + 2024 + Ryan Nemeth + · + + Powered by Hugo & Coder. + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/posts/page/4/index.html b/public/posts/page/4/index.html new file mode 100644 index 00000000..0b042798 --- /dev/null +++ b/public/posts/page/4/index.html @@ -0,0 +1,381 @@ + + + + + + Posts · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    +
    +

    + + Posts + +

    +
    + + + + + + + + + +
      + + +
    • «
    • + + + + + + + + + + + + + + + + + + + + + + +
    • 2
    • + + + + + + + + + + + + + +
    • 3
    • + + + + + + + + + + + + + +
    • 4
    • + + + + + + + + + + + + + +
    • 5
    • + + + + + + + + + + + + + +
    • 6
    • + + + + + + + + + + + + + + + + + + + + + + +
    • »
    • + + +
    + + +
    + +
    + +
    +
    + © + + 2012 - + + 2024 + Ryan Nemeth + · + + Powered by Hugo & Coder. + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/posts/page/5/index.html b/public/posts/page/5/index.html new file mode 100644 index 00000000..a797c704 --- /dev/null +++ b/public/posts/page/5/index.html @@ -0,0 +1,381 @@ + + + + + + Posts · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    +
    +

    + + Posts + +

    +
    + + + + + + + + + +
      + + +
    • «
    • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    • 3
    • + + + + + + + + + + + + + +
    • 4
    • + + + + + + + + + + + + + +
    • 5
    • + + + + + + + + + + + + + +
    • 6
    • + + + + + + + + + + + + + +
    • 7
    • + + + + + + + + + + + + + + +
    • »
    • + + +
    + + +
    + +
    + +
    +
    + © + + 2012 - + + 2024 + Ryan Nemeth + · + + Powered by Hugo & Coder. + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/posts/page/6/index.html b/public/posts/page/6/index.html new file mode 100644 index 00000000..e0347d4c --- /dev/null +++ b/public/posts/page/6/index.html @@ -0,0 +1,381 @@ + + + + + + Posts · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    +
    +

    + + Posts + +

    +
    + + + + + + + + + +
      + + +
    • «
    • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    • 4
    • + + + + + + + + + + + + + +
    • 5
    • + + + + + + + + + + + + + +
    • 6
    • + + + + + + + + + + + + + +
    • 7
    • + + + + + + + + + + + + + +
    • 8
    • + + + + + + +
    • »
    • + + +
    + + +
    + +
    + +
    +
    + © + + 2012 - + + 2024 + Ryan Nemeth + · + + Powered by Hugo & Coder. + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/posts/page/7/index.html b/public/posts/page/7/index.html new file mode 100644 index 00000000..f5f2b725 --- /dev/null +++ b/public/posts/page/7/index.html @@ -0,0 +1,381 @@ + + + + + + Posts · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    +
    +

    + + Posts + +

    +
    + + + + + + + + + +
      + + +
    • «
    • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    • 4
    • + + + + + + + + + + + + + +
    • 5
    • + + + + + + + + + + + + + +
    • 6
    • + + + + + + + + + + + + + +
    • 7
    • + + + + + + + + + + + + + +
    • 8
    • + + + + + + +
    • »
    • + + +
    + + +
    + +
    + +
    +
    + © + + 2012 - + + 2024 + Ryan Nemeth + · + + Powered by Hugo & Coder. + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/posts/page/8/index.html b/public/posts/page/8/index.html new file mode 100644 index 00000000..4d2bc815 --- /dev/null +++ b/public/posts/page/8/index.html @@ -0,0 +1,368 @@ + + + + + + Posts · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    +
    +

    + + Posts + +

    +
    + + + + + + + + + +
      + + +
    • «
    • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    • 4
    • + + + + + + + + + + + + + +
    • 5
    • + + + + + + + + + + + + + +
    • 6
    • + + + + + + + + + + + + + +
    • 7
    • + + + + + + + + + + + + + +
    • 8
    • + + + + +
    + + +
    + +
    + +
    +
    + © + + 2012 - + + 2024 + Ryan Nemeth + · + + Powered by Hugo & Coder. + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/robots.txt b/public/robots.txt index d9cec9dd..4f9540ba 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -1,5 +1 @@ -User-agent: * -# robotstxt.org - if environment is not `production` then robots will be disallowed. - - Disallow: - +User-agent: * \ No newline at end of file diff --git a/public/series/index.html b/public/series/index.html index bf263628..25e94a2d 100644 --- a/public/series/index.html +++ b/public/series/index.html @@ -1,3 +1,223 @@ -Series :: Hello Friend NG — A simple theme for Hugo \ No newline at end of file + + + + + Series · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    +
    +

    + Series +

    +
    + +
      + + +
    +
    + + +
    + +
    +
    + © + + 2012 - + + 2024 + Ryan Nemeth + · + + Powered by Hugo & Coder. + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/series/index.xml b/public/series/index.xml index 9cfbb87c..043a0ef8 100644 --- a/public/series/index.xml +++ b/public/series/index.xml @@ -1 +1,11 @@ -Series on Hello Friend NGhttps://rnemeth90.github.io/series/Recent content in Series on Hello Friend NGHugo -- gohugo.ioen-us<a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener">CC BY-NC 4.0</a> \ No newline at end of file + + + + Series on GeekyRyan + http://localhost:1313/series/ + Recent content in Series on GeekyRyan + Hugo + en + + + diff --git a/public/sitemap.xml b/public/sitemap.xml index 510abd8a..6a92e3bb 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -2,451 +2,496 @@ - https://rnemeth90.github.io/categories/ - 2023-08-15T00:00:00+00:00 + http://localhost:1313/ + 2024-12-05T00:00:00+00:00 - https://rnemeth90.github.io/tags/devops/ - 2023-08-15T00:00:00+00:00 + http://localhost:1313/posts/ + 2024-12-05T00:00:00+00:00 - https://rnemeth90.github.io/categories/devops/ - 2023-08-15T00:00:00+00:00 + http://localhost:1313/categories/ + 2024-06-29T00:00:00+00:00 - https://rnemeth90.github.io/ - 2023-08-15T00:00:00+00:00 + http://localhost:1313/tags/devops/ + 2024-06-29T00:00:00+00:00 - https://rnemeth90.github.io/posts/ - 2023-08-15T00:00:00+00:00 + http://localhost:1313/categories/kubernetes/ + 2024-06-29T00:00:00+00:00 - https://rnemeth90.github.io/tags/powershell/ - 2023-08-15T00:00:00+00:00 + http://localhost:1313/posts/2024-06-29-mount-multiple-kubernetes-secrets-into-one-directory/ + 2024-06-29T00:00:00+00:00 - https://rnemeth90.github.io/categories/powershell/ - 2023-08-15T00:00:00+00:00 + http://localhost:1313/tags/software-development/ + 2024-06-29T00:00:00+00:00 - https://rnemeth90.github.io/tags/software-development/ - 2023-08-15T00:00:00+00:00 + http://localhost:1313/tags/ + 2024-06-29T00:00:00+00:00 - https://rnemeth90.github.io/categories/software-development/ - 2023-08-15T00:00:00+00:00 + http://localhost:1313/tags/web-development/ + 2024-06-29T00:00:00+00:00 + + http://localhost:1313/posts/2024-03-27-golang-detect-file-type/ + 2024-03-27T00:00:00+00:00 + + http://localhost:1313/tags/golang/ + 2024-03-27T00:00:00+00:00 + + http://localhost:1313/categories/golang/ + 2024-03-27T00:00:00+00:00 + + http://localhost:1313/categories/software-development/ + 2024-03-27T00:00:00+00:00 + + http://localhost:1313/tags/url/ + 2024-03-27T00:00:00+00:00 + + http://localhost:1313/categories/web-development/ + 2024-03-27T00:00:00+00:00 + + http://localhost:1313/posts/2023-12-12-golang-url-validation/ + 2023-12-19T00:00:00+00:00 + + http://localhost:1313/tags/kubernetes/ + 2023-12-11T00:00:00+00:00 + + http://localhost:1313/tags/linux/ + 2023-12-11T00:00:00+00:00 + + http://localhost:1313/categories/nginx/ + 2023-12-11T00:00:00+00:00 + + http://localhost:1313/posts/2023-12-04-nginx-ingress-resp-header-size/ + 2023-12-11T00:00:00+00:00 + + http://localhost:1313/tags/nginx-ingress/ + 2023-12-11T00:00:00+00:00 + + http://localhost:1313/posts/2023-11-27-netcat/ + 2023-11-27T00:00:00+00:00 + + http://localhost:1313/categories/linux/ + 2023-11-27T00:00:00+00:00 - https://rnemeth90.github.io/tags/ + http://localhost:1313/tags/netcat/ + 2023-11-27T00:00:00+00:00 + + http://localhost:1313/categories/netcat/ + 2023-11-27T00:00:00+00:00 + + http://localhost:1313/tags/networking/ + 2023-11-27T00:00:00+00:00 + + http://localhost:1313/categories/networking/ + 2023-11-27T00:00:00+00:00 + + http://localhost:1313/categories/devops/ 2023-08-15T00:00:00+00:00 - https://rnemeth90.github.io/posts/2023-08-15-powershell-try-catch/ + http://localhost:1313/tags/powershell/ 2023-08-15T00:00:00+00:00 - https://rnemeth90.github.io/tags/golang/ - 2023-01-24T00:00:00+00:00 + http://localhost:1313/categories/powershell/ + 2023-08-15T00:00:00+00:00 - https://rnemeth90.github.io/categories/golang/ - 2023-01-24T00:00:00+00:00 + http://localhost:1313/posts/2023-08-15-powershell-try-catch/ + 2023-08-15T00:00:00+00:00 - https://rnemeth90.github.io/posts/2023-01-24-golang-strings-not-equal/ + http://localhost:1313/posts/2023-01-24-golang-strings-not-equal/ 2023-01-24T00:00:00+00:00 - https://rnemeth90.github.io/tags/c#/ - 2022-12-28T00:00:00+00:00 - - https://rnemeth90.github.io/tags/dotnet/ - 2022-12-28T00:00:00+00:00 - - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + http://localhost:1313/tags/c%23/ 2022-12-28T00:00:00+00:00 - https://rnemeth90.github.io/tags/kubernetes/ + http://localhost:1313/tags/dotnet/ 2022-12-28T00:00:00+00:00 - https://rnemeth90.github.io/categories/kubernetes/ + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ 2022-12-28T00:00:00+00:00 - https://rnemeth90.github.io/tags/sre/ + http://localhost:1313/tags/sre/ 2022-12-28T00:00:00+00:00 - https://rnemeth90.github.io/categories/sre/ + http://localhost:1313/categories/sre/ 2022-12-28T00:00:00+00:00 - https://rnemeth90.github.io/categories/azure/ + http://localhost:1313/categories/azure/ 2022-12-27T00:00:00+00:00 - https://rnemeth90.github.io/tags/backup/ + http://localhost:1313/tags/backup/ 2022-12-27T00:00:00+00:00 - https://rnemeth90.github.io/posts/2022-12-25-synology-backup-to-cloud/ + http://localhost:1313/posts/2022-12-25-synology-backup-to-cloud/ 2022-12-27T00:00:00+00:00 - https://rnemeth90.github.io/categories/synology/ + http://localhost:1313/categories/synology/ 2022-12-27T00:00:00+00:00 - https://rnemeth90.github.io/posts/2022-12-24-gh-actions-copy/ + http://localhost:1313/posts/2022-12-24-gh-actions-copy/ + 2022-12-23T00:00:00+00:00 + + http://localhost:1313/tags/ci/cd/ 2022-12-23T00:00:00+00:00 - https://rnemeth90.github.io/categories/github/ + http://localhost:1313/categories/github/ 2022-12-23T00:00:00+00:00 - https://rnemeth90.github.io/tags/github-actions/ + http://localhost:1313/tags/github-actions/ 2022-12-23T00:00:00+00:00 - https://rnemeth90.github.io/tags/azure/ + http://localhost:1313/tags/azure/ 2022-11-03T00:00:00+00:00 - https://rnemeth90.github.io/categories/azure-devops/ + http://localhost:1313/categories/azure-devops/ 2022-11-03T00:00:00+00:00 - https://rnemeth90.github.io/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ + http://localhost:1313/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ 2022-11-03T00:00:00+00:00 - https://rnemeth90.github.io/tags/software/ + http://localhost:1313/tags/software/ 2022-11-03T00:00:00+00:00 - https://rnemeth90.github.io/posts/2022-09-12-update-azure-devops-spn-secret/ + http://localhost:1313/posts/2022-09-12-update-azure-devops-spn-secret/ 2022-09-12T00:00:00+00:00 - https://rnemeth90.github.io/tags/dev/ + http://localhost:1313/tags/dev/ 2022-09-06T00:00:00+00:00 - https://rnemeth90.github.io/tags/programming/ + http://localhost:1313/tags/programming/ 2022-09-06T00:00:00+00:00 - https://rnemeth90.github.io/posts/2022-09-06-go-mod-replace-copy/ + http://localhost:1313/posts/2022-09-06-go-mod-replace-copy/ 2022-09-06T00:00:00+00:00 - https://rnemeth90.github.io/tags/json/ + http://localhost:1313/tags/json/ 2022-08-04T00:00:00+00:00 - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ 2022-08-04T00:00:00+00:00 - https://rnemeth90.github.io/tags/rest/ + http://localhost:1313/tags/rest/ 2022-08-04T00:00:00+00:00 - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ + http://localhost:1313/posts/2022-07-21-reading-json-files-with-go/ 2022-07-21T00:00:00+00:00 - https://rnemeth90.github.io/tags/aks/ + http://localhost:1313/tags/aks/ 2022-07-19T00:00:00+00:00 - https://rnemeth90.github.io/posts/2022-07-19-aks-scale-down-mode/ + http://localhost:1313/posts/2022-07-19-aks-scale-down-mode/ 2022-07-19T00:00:00+00:00 - https://rnemeth90.github.io/tags/azure-kubernetes-service/ + http://localhost:1313/tags/azure-kubernetes-service/ 2022-07-19T00:00:00+00:00 - https://rnemeth90.github.io/categories/azure-kubernetes-service/ + http://localhost:1313/categories/azure-kubernetes-service/ 2022-07-19T00:00:00+00:00 - https://rnemeth90.github.io/tags/storage/ + http://localhost:1313/tags/storage/ 2022-07-19T00:00:00+00:00 - https://rnemeth90.github.io/categories/docker/ + http://localhost:1313/categories/docker/ 2022-07-15T18:18:50+00:00 - https://rnemeth90.github.io/tags/linux/ + http://localhost:1313/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ 2022-07-15T18:18:50+00:00 - https://rnemeth90.github.io/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ - 2022-07-15T18:18:50+00:00 - - https://rnemeth90.github.io/tags/docker/ + http://localhost:1313/tags/docker/ 2022-06-26T15:00:28+00:00 - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ 2022-06-26T15:00:28+00:00 - https://rnemeth90.github.io/categories/software-deployment/ + http://localhost:1313/categories/software-deployment/ 2022-06-26T15:00:28+00:00 - https://rnemeth90.github.io/categories/.net/ + http://localhost:1313/categories/.net/ 2022-06-12T13:58:52+00:00 - https://rnemeth90.github.io/categories/.net-core/ + http://localhost:1313/categories/.net-core/ 2022-06-12T13:58:52+00:00 - https://rnemeth90.github.io/categories/c#/ + http://localhost:1313/categories/c%23/ 2022-06-12T13:58:52+00:00 - https://rnemeth90.github.io/tags/database/ + http://localhost:1313/tags/database/ 2022-06-12T13:58:52+00:00 - https://rnemeth90.github.io/tags/ef-core/ + http://localhost:1313/tags/ef-core/ 2022-06-12T13:58:52+00:00 - https://rnemeth90.github.io/categories/ef-core/ + http://localhost:1313/categories/ef-core/ 2022-06-12T13:58:52+00:00 - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ 2022-06-12T13:58:52+00:00 - https://rnemeth90.github.io/tags/entity-framework/ + http://localhost:1313/tags/entity-framework/ 2022-06-12T13:58:52+00:00 - https://rnemeth90.github.io/categories/entity-framework-core/ + http://localhost:1313/categories/entity-framework-core/ 2022-06-12T13:58:52+00:00 - https://rnemeth90.github.io/tags/bash/ + http://localhost:1313/tags/bash/ 2022-06-04T18:29:41+00:00 - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ 2022-06-04T18:29:41+00:00 - https://rnemeth90.github.io/posts/2022-04-30-injecting-multiple-kubernetes-volumes-to-the-same-directory-in-a-pod/ + http://localhost:1313/posts/2022-04-30-injecting-multiple-kubernetes-volumes-to-the-same-directory-in-a-pod/ 2022-04-30T14:21:05+00:00 - https://rnemeth90.github.io/categories/uncategorized/ + http://localhost:1313/categories/uncategorized/ 2022-04-30T14:21:05+00:00 - https://rnemeth90.github.io/posts/2022-03-01-kubernetes-storage-simplified/ + http://localhost:1313/posts/2022-03-01-kubernetes-storage-simplified/ 2022-03-01T08:37:58+00:00 - https://rnemeth90.github.io/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ + http://localhost:1313/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ 2022-02-19T16:02:50+00:00 - https://rnemeth90.github.io/tags/failed-pod/ + http://localhost:1313/categories/ci/cd/ + 2022-02-19T16:02:50+00:00 + + http://localhost:1313/tags/failed-pod/ 2022-02-05T23:49:16+00:00 - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ 2022-02-05T23:49:16+00:00 - https://rnemeth90.github.io/tags/pod-eviction/ + http://localhost:1313/tags/pod-eviction/ 2022-02-05T23:49:16+00:00 - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ + http://localhost:1313/posts/2022-01-16-azure-kubernetes-sftp-solution/ 2022-01-16T07:00:00+00:00 - https://rnemeth90.github.io/tags/ftp/ + http://localhost:1313/tags/ftp/ 2022-01-16T07:00:00+00:00 - https://rnemeth90.github.io/categories/sftp/ + http://localhost:1313/categories/sftp/ 2022-01-16T07:00:00+00:00 - https://rnemeth90.github.io/posts/2022-01-14-wsus-update-files-not-downloading/ + http://localhost:1313/posts/2022-01-14-wsus-update-files-not-downloading/ 2022-01-14T22:01:40+00:00 - https://rnemeth90.github.io/posts/2022-01-14-active-directory-migration-toolkit-the-rpc-server-is-unavailable/ + http://localhost:1313/posts/2022-01-14-active-directory-migration-toolkit-the-rpc-server-is-unavailable/ 2022-01-14T21:55:56+00:00 - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ + http://localhost:1313/posts/2022-01-14-continuous-deployment-models/ 2022-01-14T19:24:01+00:00 - https://rnemeth90.github.io/tags/software-deployment/ + http://localhost:1313/tags/software-deployment/ 2022-01-14T19:24:01+00:00 - https://rnemeth90.github.io/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ + http://localhost:1313/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ 2022-01-14T18:46:35+00:00 - https://rnemeth90.github.io/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ + http://localhost:1313/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ 2022-01-14T18:45:00+00:00 - https://rnemeth90.github.io/posts/2022-01-14-azure-tenant-maintenance-purge-empty-resource-groups/ + http://localhost:1313/posts/2022-01-14-azure-tenant-maintenance-purge-empty-resource-groups/ 2022-01-14T18:43:35+00:00 - https://rnemeth90.github.io/tags/certification/ + http://localhost:1313/tags/certification/ 2020-12-16T14:44:00+00:00 - https://rnemeth90.github.io/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ + http://localhost:1313/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ 2020-12-16T14:44:00+00:00 - https://rnemeth90.github.io/tags/activedirectory/ + http://localhost:1313/tags/activedirectory/ 2020-11-26T16:31:00+00:00 - https://rnemeth90.github.io/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ + http://localhost:1313/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ 2020-11-26T16:31:00+00:00 - https://rnemeth90.github.io/tags/office365/ + http://localhost:1313/tags/office365/ 2020-11-26T16:31:00+00:00 - https://rnemeth90.github.io/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ - 2020-11-19T18:07:00+00:00 - - https://rnemeth90.github.io/tags/networking/ + http://localhost:1313/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ 2020-11-19T18:07:00+00:00 - https://rnemeth90.github.io/tags/vmss/ + http://localhost:1313/tags/vmss/ 2020-11-19T18:07:00+00:00 - https://rnemeth90.github.io/posts/2020-11-17-azure-policy-allowed-locations-for/ + http://localhost:1313/posts/2020-11-17-azure-policy-allowed-locations-for/ 2020-11-17T17:52:00+00:00 - https://rnemeth90.github.io/tags/security/ + http://localhost:1313/tags/security/ 2020-11-17T17:52:00+00:00 - https://rnemeth90.github.io/posts/2020-11-03-replicate-azure-vm-image-between-regions/ + http://localhost:1313/posts/2020-11-03-replicate-azure-vm-image-between-regions/ 2020-11-03T20:15:00+00:00 - https://rnemeth90.github.io/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ + http://localhost:1313/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ 2020-10-31T01:22:00+00:00 - https://rnemeth90.github.io/tags/vmware/ + http://localhost:1313/tags/vmware/ 2020-10-31T01:22:00+00:00 - https://rnemeth90.github.io/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ + http://localhost:1313/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ 2020-10-31T01:02:00+00:00 - https://rnemeth90.github.io/tags/windowsserver/ + http://localhost:1313/tags/windowsserver/ 2020-10-31T01:02:00+00:00 - https://rnemeth90.github.io/posts/2020-10-28-could-not-connect-to-vmware-directory/ + http://localhost:1313/posts/2020-10-28-could-not-connect-to-vmware-directory/ 2020-10-28T13:51:00+00:00 - https://rnemeth90.github.io/tags/cisco/ + http://localhost:1313/tags/cisco/ 2020-10-07T13:28:00+00:00 - https://rnemeth90.github.io/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ + http://localhost:1313/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ 2020-10-07T13:28:00+00:00 - https://rnemeth90.github.io/tags/tools/ + http://localhost:1313/tags/tools/ 2020-10-07T13:28:00+00:00 - https://rnemeth90.github.io/tags/windows-client-os/ + http://localhost:1313/tags/windows-client-os/ 2020-10-07T13:28:00+00:00 - https://rnemeth90.github.io/posts/2019-01-14-error-when-reinstalling-dirsync/ + http://localhost:1313/posts/2019-01-14-error-when-reinstalling-dirsync/ 2019-01-14T21:47:04+00:00 - https://rnemeth90.github.io/posts/2018-08-21-active-directory-migration-toolkit-rpc/ + http://localhost:1313/posts/2018-08-21-active-directory-migration-toolkit-rpc/ 2018-08-21T17:34:00+00:00 - https://rnemeth90.github.io/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ + http://localhost:1313/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ 2018-08-21T17:26:00+00:00 - https://rnemeth90.github.io/tags/aadconnect/ + http://localhost:1313/tags/aadconnect/ 2018-07-26T12:22:00+00:00 - https://rnemeth90.github.io/posts/2018-07-26-azure-ad-connect-no-start-connection/ + http://localhost:1313/posts/2018-07-26-azure-ad-connect-no-start-connection/ 2018-07-26T12:22:00+00:00 - https://rnemeth90.github.io/tags/dirsync/ + http://localhost:1313/tags/dirsync/ 2018-07-26T12:22:00+00:00 - https://rnemeth90.github.io/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ + http://localhost:1313/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ 2018-07-18T16:38:00+00:00 - https://rnemeth90.github.io/posts/2018-07-13-removing-forest-from-azure-ad-connect/ + http://localhost:1313/posts/2018-07-13-removing-forest-from-azure-ad-connect/ 2018-07-13T15:30:00+00:00 - https://rnemeth90.github.io/posts/2017-11-08-remove-stubborn-psc-or-vcenter/ + http://localhost:1313/posts/2017-11-08-remove-stubborn-psc-or-vcenter/ 2017-11-08T07:56:00+00:00 - https://rnemeth90.github.io/tags/exchange/ + http://localhost:1313/tags/exchange/ 2017-11-07T13:30:00+00:00 - https://rnemeth90.github.io/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ + http://localhost:1313/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ 2017-11-07T13:30:00+00:00 - https://rnemeth90.github.io/posts/2017-06-27-migrate-windows-deployment-services-to-new-server/ + http://localhost:1313/posts/2017-06-27-migrate-windows-deployment-services-to-new-server/ 2017-06-27T09:21:00+00:00 - https://rnemeth90.github.io/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ + http://localhost:1313/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ 2017-06-26T22:16:00+00:00 - https://rnemeth90.github.io/posts/2017-06-22-windows-8-file-history-windows-8-file-history/ + http://localhost:1313/posts/2017-06-22-windows-8-file-history-windows-8-file-history/ 2017-06-22T22:42:00+00:00 - https://rnemeth90.github.io/posts/2017-06-20-how-to-permanently-remove-office-365-users/ + http://localhost:1313/posts/2017-06-20-how-to-permanently-remove-office-365-users/ 2017-06-20T18:13:00+00:00 - https://rnemeth90.github.io/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ + http://localhost:1313/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ 2017-06-12T13:41:00+00:00 - https://rnemeth90.github.io/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/ + http://localhost:1313/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/ 2017-05-29T01:09:00+00:00 - https://rnemeth90.github.io/tags/wsus/ + http://localhost:1313/tags/wsus/ 2016-11-18T15:13:00+00:00 - https://rnemeth90.github.io/posts/2016-11-18-wsus-update-files-not-downloading/ + http://localhost:1313/posts/2016-11-18-wsus-update-files-not-downloading/ 2016-11-18T15:13:00+00:00 - https://rnemeth90.github.io/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ + http://localhost:1313/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ 2016-11-10T15:18:00+00:00 - https://rnemeth90.github.io/tags/wds/ + http://localhost:1313/tags/wds/ 2016-11-10T02:19:00+00:00 - https://rnemeth90.github.io/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ + http://localhost:1313/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ 2016-11-10T02:19:00+00:00 - https://rnemeth90.github.io/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ + http://localhost:1313/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ 2016-10-06T03:03:00+00:00 - https://rnemeth90.github.io/tags/scripts/ + http://localhost:1313/tags/scripts/ 2016-10-06T03:03:00+00:00 - https://rnemeth90.github.io/categories/exchange/ + http://localhost:1313/categories/exchange/ 2016-10-04T00:21:00+00:00 - https://rnemeth90.github.io/posts/2016-10-04-exchange-2013-error-0x80070070-while/ + http://localhost:1313/posts/2016-10-04-exchange-2013-error-0x80070070-while/ 2016-10-04T00:21:00+00:00 - https://rnemeth90.github.io/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ + http://localhost:1313/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ 2016-04-11T01:25:00+00:00 - https://rnemeth90.github.io/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ + http://localhost:1313/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ 2015-12-30T10:38:00+00:00 - https://rnemeth90.github.io/posts/2015-10-15-azure-ad-connect-password-sync-disabled/ + http://localhost:1313/posts/2015-10-15-azure-ad-connect-password-sync-disabled/ 2015-10-15T10:18:00+00:00 - https://rnemeth90.github.io/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ + http://localhost:1313/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ 2015-09-07T23:13:00+00:00 - https://rnemeth90.github.io/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ + http://localhost:1313/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ 2015-09-01T21:05:00+00:00 - https://rnemeth90.github.io/posts/2015-08-13-error-when-reinstalling-dirsync/ + http://localhost:1313/posts/2015-08-13-error-when-reinstalling-dirsync/ 2015-08-13T18:59:00+00:00 - https://rnemeth90.github.io/posts/2015-08-12-failed-to-mount-exchange-2010-database/ + http://localhost:1313/posts/2015-08-12-failed-to-mount-exchange-2010-database/ 2015-08-12T12:59:00+00:00 - https://rnemeth90.github.io/posts/2015-03-09-ping-sweeping-with-fping/ + http://localhost:1313/posts/2015-03-09-ping-sweeping-with-fping/ 2015-03-09T01:08:00+00:00 - https://rnemeth90.github.io/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ + http://localhost:1313/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ 2014-12-08T13:43:00+00:00 - https://rnemeth90.github.io/tags/dhcp/ + http://localhost:1313/tags/dhcp/ 2014-12-08T03:08:00+00:00 - https://rnemeth90.github.io/posts/2014-12-08-dhcp-address-negotiation-process/ + http://localhost:1313/posts/2014-12-08-dhcp-address-negotiation-process/ 2014-12-08T03:08:00+00:00 - https://rnemeth90.github.io/posts/2014-12-08-unlock-domain-user-from-cmd-line/ + http://localhost:1313/posts/2014-12-08-unlock-domain-user-from-cmd-line/ 2014-12-08T02:11:00+00:00 - https://rnemeth90.github.io/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ + http://localhost:1313/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ 2014-11-25T01:27:00+00:00 - https://rnemeth90.github.io/posts/2014-11-17-creating-applocker-policies/ + http://localhost:1313/posts/2014-11-17-creating-applocker-policies/ 2014-11-17T01:40:00+00:00 - https://rnemeth90.github.io/posts/2014-11-16-tcpip-network-fundamentals/ + http://localhost:1313/posts/2014-11-16-tcpip-network-fundamentals/ 2014-11-16T21:20:00+00:00 - https://rnemeth90.github.io/posts/2014-11-16-branchcache/ + http://localhost:1313/posts/2014-11-16-branchcache/ 2014-11-16T21:16:00+00:00 - https://rnemeth90.github.io/posts/2014-11-15-file-history/ + http://localhost:1313/posts/2014-11-15-file-history/ 2014-11-15T20:02:00+00:00 - https://rnemeth90.github.io/tags/windows/ + http://localhost:1313/tags/windows/ 2014-11-15T20:02:00+00:00 - https://rnemeth90.github.io/posts/2012-11-16-layer-2-switching-fundamentals/ - 2012-11-16T21:26:00+00:00 - - https://rnemeth90.github.io/categories/networking/ + http://localhost:1313/posts/2012-11-16-layer-2-switching-fundamentals/ 2012-11-16T21:26:00+00:00 - https://rnemeth90.github.io/posts/2012-11-15-user-account-control-copy/ + http://localhost:1313/posts/2012-11-15-user-account-control-copy/ 2012-11-15T16:01:00+00:00 - https://rnemeth90.github.io/posts/2012-11-15-user-account-control/ + http://localhost:1313/posts/2012-11-15-user-account-control/ 2012-11-15T16:01:00+00:00 - https://rnemeth90.github.io/about/ + http://localhost:1313/about/ - https://rnemeth90.github.io/tags/ci/cd/ + http://localhost:1313/authors/ - https://rnemeth90.github.io/categories/ci/cd/ + http://localhost:1313/series/ diff --git a/public/tags/aadconnect/index.html b/public/tags/aadconnect/index.html index e6924e21..64dad530 100644 --- a/public/tags/aadconnect/index.html +++ b/public/tags/aadconnect/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: AADConnect · GeekyRyan + - - -AADConnect - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,295 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Tag: AADConnect

    - - - -
    -
    -
    -

    Azure AD Connect No-Start-Connection

    -
    -
    +
    +
    + © -
    - This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working. -After forcing the sync, I opened miisclient and noticed some strange errors. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2018-07-26-azure-ad-connect-no-start-connection/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/aadconnect/index.xml b/public/tags/aadconnect/index.xml index e87cbdc2..9ac11652 100644 --- a/public/tags/aadconnect/index.xml +++ b/public/tags/aadconnect/index.xml @@ -2,29 +2,18 @@ AADConnect on GeekyRyan - https://rnemeth90.github.io/tags/aadconnect/ - GeekyRyan (AADConnect) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/aadconnect/ + Recent content in AADConnect on GeekyRyan + Hugo + en Thu, 26 Jul 2018 12:22:00 +0000 - - - - + Azure AD Connect No-Start-Connection - https://rnemeth90.github.io/posts/2018-07-26-azure-ad-connect-no-start-connection/ + http://localhost:1313/posts/2018-07-26-azure-ad-connect-no-start-connection/ Thu, 26 Jul 2018 12:22:00 +0000 - - https://rnemeth90.github.io/posts/2018-07-26-azure-ad-connect-no-start-connection/ - <p>This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working.</p> -<p>After forcing the sync, I opened miisclient and noticed some strange errors. We sync multiple on-prem AD forests to Azure AD, and the status for one of them was “no-start-connection”. That error in itself does not seem significant to me. However, after clicking on the “failed-connection” link in the Connection Status pane, things became much more clear.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_05.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_05.png" alt=""></a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_18.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_18.png" alt=""></a></p> -<p>The domain controllers for the forest in question are in a datacenter that is geographically separated from the datacenter that our Azure AD Sync server lives in. The two sites are connected via a S2S VPN.</p> -<p>There was obviously some type of connection issue between our two datacenters. In my case, the issue was transient, and resolved itself after a few minutes. But if you’re experiencing this error message, check your L2/L3 connection. Also, verify DNS is working and someone didn’t make changes to your firewall(s). Just walk up or down the OSI model and you’ll eventually find the problem.</p> - + http://localhost:1313/posts/2018-07-26-azure-ad-connect-no-start-connection/ + This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working. After forcing the sync, I opened miisclient and noticed some strange errors. - diff --git a/public/tags/aadconnect/page/1/index.html b/public/tags/aadconnect/page/1/index.html index 21b12f1d..e575c716 100644 --- a/public/tags/aadconnect/page/1/index.html +++ b/public/tags/aadconnect/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/aadconnect/ - + http://localhost:1313/tags/aadconnect/ + - + diff --git a/public/tags/activedirectory/index.html b/public/tags/activedirectory/index.html index a3203365..6cb695dc 100644 --- a/public/tags/activedirectory/index.html +++ b/public/tags/activedirectory/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: ActiveDirectory · GeekyRyan + - - -ActiveDirectory - GeekyRyan - - - - - - - - - - - + - - + + + - + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,857 +79,232 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - - -
    -
    - -

    Tag: ActiveDirectory

    - - - -
    -
    -
    -

    Azure AD Sync &#8211; Set-MsolDirSyncEnabled : You cannot turn off Active Directory synchronization.

    -
    - -
    - - -
    - I recently ran into a situation in my lab environment that required I resync all (2000+) user accounts to Azure AD. Though this sounds complex and daunting, its actually quite simple. T -The basic steps involve disabling sync, and then removing the user objects. This can all be done with two PowerShell commands: -1) Set-MsolDirSyncEnabled -EnableDirSync $false -2) Get-MsolUser -All | Remove-MsolUser -force -The account that you are currently running the commands as will not be removed. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Deploy a New ADDS Forest on Server 2019 Core

    -
    - -
    - - -
    - Prerequisites: -Change server name and IP address Configure time settings and NTP -In this post we will be reviewing the basic installation of the Active Directory Domain Services role and setup of a new forest on Windows Server Core 2019. -To get started, login to your server with administrator privileges. You will first need to type in “powershell” in the cmd prompt to start powershell. Once you do that, type in the following command to install the Active Directory Domain Services role: -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Active Directory Migration Toolkit &#8211; The RPC Server is Unavailable (hr=0x800706ba)

    -
    - -
    - - -
    - When migrating computer objects using the Active Directory Migration Tool, you may encounter the following error: -In addition, the Migration Log may show the following error: -This is typically caused by a host-side firewall. To resolve this, deploy a GPO to disable the Windows firewall prior to migrating the computer account. I like to create a special OU for computers (I typically name it “PreMigration”) that I will move computer objects to prior to migrating them. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Azure AD Connect No-Start-Connection

    -
    - -
    - -
    - This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working. -After forcing the sync, I opened miisclient and noticed some strange errors. -
    - - -
    - Read more -
    - - - - -
    - -
    -
    -
    -

    Azure AD Connect Health: Latest Data is not Available in Azure Portal

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Tag: ActiveDirectory +

    +
    + +
      -
      - I recently had to create a new Azure AD Connect server, and found that it was not able to report health status in the Azure Portal. After some troubleshooting/research, I was able to get the health status report working by registering the health agent on the server with Azure AD Health Services. Doing this involves running one PowerShell cmdlet on your AD Connect server and providing global administrator credentials. -First, let’s test the status of the agent communication: -
      - - -
      - Read more -
      - - - - - - - - - -
    +
  • + 2020-11-26 + Azure AD Sync &#8211; Set-MsolDirSyncEnabled : You cannot turn off Active Directory synchronization. +
  • -
    -
    -
    -

    Removing a Forest from Azure AD Connect

    -
    - -
    - +
  • + 2020-10-31 + Deploy a New ADDS Forest on Server 2019 Core +
  • -
    - In an organization with multiple Active Directory forests, you may want to sync objects from trusted forests. Adding trusted forests to Azure AD Sync is a simple process that I will likely cover in a future article. The focus of this post is the not-so-obvious process of removing a forest from Azure AD Connect. This can be a daunting and somewhat scary thing to do. Not fully understanding the process or having someone to guide you can leave you with thoughts like “what happens when I remove the forest from Azure AD Sync? -
    +
  • + 2018-08-21 + Active Directory Migration Toolkit &#8211; The RPC Server is Unavailable (hr=0x800706ba) +
  • +
  • + 2018-07-26 + Azure AD Connect No-Start-Connection +
  • -
    - Read more -
    +
  • + 2018-07-18 + Azure AD Connect Health: Latest Data is not Available in Azure Portal +
  • +
  • + 2018-07-13 + Removing a Forest from Azure AD Connect +
  • +
  • + 2017-06-12 + Access is Denied When Attempting to Delete a Dynamic Distribution Group +
  • - +
  • + 2015-12-30 + The User Profile Service service failed the logon +
  • - - - - -
    - -
    -
    -
    -

    Access is Denied When Attempting to Delete a Dynamic Distribution Group

    -
    - -
    - -
    - You may receive the error below when attempting to delete a dynamic distribution group. -To resolve this, open ADUC and show advanced features (Click View > Advanced Features). Then find the object for the dynamic distribution group and open the properties window. Browse to the “Object” tab and uncheck the “Protect object from accidental deletion” box. Wait for ADDS to replicate or force replication yourself. -Go back to the ECP and you should be able to delete the group. -
    - - -
    - Read more -
    - - - - - - -
    + -
    -
    -
    -

    The User Profile Service service failed the logon

    -
    - -
    - -
    - One of my clients had a really strange issue the other day. He has a domain admin account in his domain and was not able to login to a server that I recently built. The server was an Exchange 2013 box, and was used in Coexistence mode to migrate his company from an Exchange 2007 box. -He was getting this error message when attempting to login: -This is a classic error message that I’m sure most technicians have seen before. -
    + +
  • 1
  • + + -
    - Read more -
    + - + +
  • 2
  • + - - - -
    - -
    -
    -
    -

    Script for Querying All AD Computers Time Source

    -
    -
    +
    +
    + © -
    - This script will iterate through all computers in Active Directory and return the configured time server for each computer. -<# .SYNOPSIS Get time source for all computers in domain .EXAMPLE Get-TimeSource .NOTES Author: Ryan Nemeth - RyanNemeth@live.com Site: http://www.geekyryan.com .LINK http://www.geekyryan.com .DESCRIPTION This function will iterate through all computers/servers in a domain and return the time source for each. #> Write-Host -foregroundcolor Red -BackgroundColor black "This script must be run on a domain controller and requires that the AD Powershell module be installed" $module = Get-Module -ListAvailable | Select-Object -ExpandProperty Name if($module -notcontains "ActiveDirectory") { Write-Host -foregroundcolor red -backgroundcolor black "***Active Directory Powershell Module Not Found***" } else { Write-Host -foregroundcolor yellow "Found Active Directory Powershell Module. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - - -
    +
    +
    -
    - - - - - - -
    -
    + - - -
    -
    -
    -

    Powershell: SID to Username

    -
    - -
    + + + + - -
    - This is a simple script to convert a SID to a username -# Returns a username based on a SID # Author: Ryan Nemeth # Date: 12/2/2014 $SID = read-host “Please enter the SID: ” $object = New-Object System.Security.Principal.SecurityIdentifier($SID) $User = $object.Translate( \[System.Security.Principal.NTAccount\]) write-host “The user is: ” $User.Value -
    - - - - + - + - - -
    - - - - - + + + + - - -
    - - + - + -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/activedirectory/index.xml b/public/tags/activedirectory/index.xml index 37a824c8..450ab3ec 100644 --- a/public/tags/activedirectory/index.xml +++ b/public/tags/activedirectory/index.xml @@ -2,289 +2,95 @@ ActiveDirectory on GeekyRyan - https://rnemeth90.github.io/tags/activedirectory/ - GeekyRyan (ActiveDirectory) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/activedirectory/ + Recent content in ActiveDirectory on GeekyRyan + Hugo + en Thu, 26 Nov 2020 16:31:00 +0000 - - - - + Azure AD Sync &#8211; Set-MsolDirSyncEnabled : You cannot turn off Active Directory synchronization. - https://rnemeth90.github.io/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ + http://localhost:1313/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ Thu, 26 Nov 2020 16:31:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ - <p>I recently ran into a situation in my lab environment that required I resync all (2000+) user accounts to Azure AD. Though this sounds complex and daunting, its actually quite simple. T</p> -<p>The basic steps involve disabling sync, and then removing the user objects. This can all be done with two PowerShell commands:</p> -<p>1) Set-MsolDirSyncEnabled -EnableDirSync $false</p> -<p><a href="https://lh3.googleusercontent.com/-rGK18FXw7ns/X7_WthQR0CI/AAAAAAAAyCM/gg7MsY2fcVIcWMMbvxYzPpbpPyKwgHP8ACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image.png" alt=""></a></p> -<p>2) Get-MsolUser -All | Remove-MsolUser -force</p> -<p><a href="https://lh3.googleusercontent.com/-miyfN7OISGo/X7_WzDCc6iI/AAAAAAAAyCQ/PtHURTTVMQ4uypzO7L1UaLfyEs0fpYGdACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-1.png" alt=""></a></p> -<p>The account that you are currently running the commands as will not be removed.</p> -<p>To enable Azure AD Sync, you simply reverse the boolean operation on the Set-MsolDirSyncEnabled cmdlet above. However, I ran into an issue when trying to enable Azure AD Sync.</p> -<p><a href="https://lh3.googleusercontent.com/-R1TPVgYaEBE/X7_XM5_ljKI/AAAAAAAAyCY/VIJZnlgNEPQbhL9p3D0J3XsekBrGiNS3QCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-2.png" alt=""></a></p> -<p>After some research, it turns out you must wait a period of time (up to 12 hours in some cases) before you can make a second change to the Azure AD Sync status. This error simply means that we made a recent change to Azure AD Sync, and we must wait before making another change. To prove this, there is a “DirectorySynchronizationStatus” member for the Get-MsolCompanyInformation cmdlet. If we take a look at this member, we can see the status is “PendingDisabled”.</p> -<p><a href="https://lh3.googleusercontent.com/-0OBwKDDD5xQ/X7_X1bBxXjI/AAAAAAAAyCk/FyRlaMpCDT4aBe08TL_8sLiwUBnHkcPJQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-3.png" alt=""></a></p> -<p>Check the status of this periodically over the next 12 hours or so, and once it says “Enabled” or “Disabled”, you should be able to change the state once more.</p> - + http://localhost:1313/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ + I recently ran into a situation in my lab environment that required I resync all (2000+) user accounts to Azure AD. Though this sounds complex and daunting, its actually quite simple. T The basic steps involve disabling sync, and then removing the user objects. This can all be done with two PowerShell commands: 1) Set-MsolDirSyncEnabled -EnableDirSync $false 2) Get-MsolUser -All | Remove-MsolUser -force The account that you are currently running the commands as will not be removed. - Deploy a New ADDS Forest on Server 2019 Core - https://rnemeth90.github.io/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ + http://localhost:1313/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ Sat, 31 Oct 2020 01:02:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ - <p>Prerequisites:</p> -<p>Change server name and IP address -Configure time settings and NTP</p> -<p>In this post we will be reviewing the basic installation of the Active Directory Domain Services role and setup of a new forest on Windows Server Core 2019.</p> -<p>To get started, login to your server with administrator privileges. You will first need to type in “powershell” in the cmd prompt to start powershell. Once you do that, type in the following command to install the Active Directory Domain Services role:</p> -<p><a href="https://lh3.googleusercontent.com/-LnSTbXjG2Hc/X5y3R3F-eWI/AAAAAAAAx2A/lWQBpA44Dmo-Jpbck2iPmgibU6z0DM1YwCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-12.png" alt=""></a></p> -<p>After installing the role, we’ll continue by creating a new ADDS Forest and promoting this server to the primary domain controller.</p> -<p>First, we’ll need to gather a password. This password will not be used for a domain user account. The local administrator on this server will become the domain administrator account for the domain. The password we’re gathering in the next step will be used for Directory Services Restore Mode (DSRM). DSRM is a recovery mode used to recover domain controllers that won’t boot up. We technically only need a password, not a username for this account.</p> -<p>Type in the following:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$cred = Get-Credential -</span></span></code></pre></div><p>In the username field for the credentials prompt below, just type in anything you want, as the value will not be used. This prompt will store our username/password in a variable object. We can then access the password within the credential object by typing:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$cred.password -</span></span></code></pre></div><p>We can see that this password is stored as a secure string object. Let’s continue on with the Directory Services installation.</p> -<p><a href="https://lh3.googleusercontent.com/-n-W0yvwr2Zs/X5y3X64NjZI/AAAAAAAAx2E/rx5urA7p_NMl3peX5g0J7Ax7biWwNADAgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-13.png" alt=""></a></p> -<p><a href="https://lh3.googleusercontent.com/-0k-aZrMhyGw/X5y3ckH10pI/AAAAAAAAx2I/FS56uvXCirAaBHKwWmIRQ4xIGU_jp_GFwCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-14.png" alt=""></a></p> -<p>Once we have our credential variable, we can install a new forest and domain controller using the command below. Let us break down what this cmd is doing:</p> -<p><a href="https://lh3.googleusercontent.com/-OF_HVfCPZIM/X5y3ijEA5YI/AAAAAAAAx2M/0vMV3CJczT8D3q5x8hzPAZVSL5DycplBACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-15.png" alt=""></a></p> -<p>Install-ADDSForest: The powershell cmdlet to create a new forest and domain controller</p> -<p>-DomainName: The domain name to be used for the forest</p> -<p>-DomainNetBiosName: The domain “Short name” to be used for the forest. This is the value used when you type in a username in the domainusername format. Example “myDomainbgates”.</p> -<p>-SafeModeAdministratorPassword: The value we captured in our credential prompt above. This is used for Directory Services Restore Mode. This mode can be accessed by pressing F8 while the server is booting. It is commonly used for recovering a failed domain controller.</p> -<p>-DatabasePath: The path for the Active Directory database. It’s a best practice to put this database on its own disk.</p> -<p>-LogPath: The directory for ADDS log files</p> -<p>-DomainMode: The domain functional level. The domain functional level specifies the attributes and capabilities available to objects within the domain. The higher the level you choose, the more features will be available to you.</p> -<p>-ForestMode: The forest functional level. Similar to the domain functional level but applies to the entire forest.</p> -<p>-InstallDNS: Install the DNS role alongside the ADDS role.</p> -<p>-WhatIf: This is a powershell “thing”. Most cmdlets have the “whatif” parameter. It basically allows you to run the cmdlet in “test” mode without actually making any changes to your environment. Once you’re happy with the output, you can remove the “whatif” parameter and run the command to install ADDS and promote this server to a domain controller.</p> - + http://localhost:1313/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ + Prerequisites: Change server name and IP address Configure time settings and NTP In this post we will be reviewing the basic installation of the Active Directory Domain Services role and setup of a new forest on Windows Server Core 2019. To get started, login to your server with administrator privileges. You will first need to type in “powershell” in the cmd prompt to start powershell. Once you do that, type in the following command to install the Active Directory Domain Services role: - Active Directory Migration Toolkit &#8211; The RPC Server is Unavailable (hr=0x800706ba) - https://rnemeth90.github.io/posts/2018-08-21-active-directory-migration-toolkit-rpc/ + http://localhost:1313/posts/2018-08-21-active-directory-migration-toolkit-rpc/ Tue, 21 Aug 2018 17:34:00 +0000 - - https://rnemeth90.github.io/posts/2018-08-21-active-directory-migration-toolkit-rpc/ - <p>When migrating computer objects using the Active Directory Migration Tool, you may encounter the following error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_09.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_09.png" alt=""></a></p> -<p>In addition, the Migration Log may show the following error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-03_11h20_20.png" alt=""></a></p> -<p>This is typically caused by a host-side firewall. To resolve this, deploy a GPO to disable the Windows firewall prior to migrating the computer account. I like to create a special OU for computers (I typically name it “PreMigration”) that I will move computer objects to prior to migrating them. This OU will have two policies applied. One to disable the Windows Firewall and another to start the Remote Registry service. Both are required for the computer object to successfully migrate.</p> - + http://localhost:1313/posts/2018-08-21-active-directory-migration-toolkit-rpc/ + When migrating computer objects using the Active Directory Migration Tool, you may encounter the following error: In addition, the Migration Log may show the following error: This is typically caused by a host-side firewall. To resolve this, deploy a GPO to disable the Windows firewall prior to migrating the computer account. I like to create a special OU for computers (I typically name it “PreMigration”) that I will move computer objects to prior to migrating them. - Azure AD Connect No-Start-Connection - https://rnemeth90.github.io/posts/2018-07-26-azure-ad-connect-no-start-connection/ + http://localhost:1313/posts/2018-07-26-azure-ad-connect-no-start-connection/ Thu, 26 Jul 2018 12:22:00 +0000 - - https://rnemeth90.github.io/posts/2018-07-26-azure-ad-connect-no-start-connection/ - <p>This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working.</p> -<p>After forcing the sync, I opened miisclient and noticed some strange errors. We sync multiple on-prem AD forests to Azure AD, and the status for one of them was “no-start-connection”. That error in itself does not seem significant to me. However, after clicking on the “failed-connection” link in the Connection Status pane, things became much more clear.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_05.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_05.png" alt=""></a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_18.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_18.png" alt=""></a></p> -<p>The domain controllers for the forest in question are in a datacenter that is geographically separated from the datacenter that our Azure AD Sync server lives in. The two sites are connected via a S2S VPN.</p> -<p>There was obviously some type of connection issue between our two datacenters. In my case, the issue was transient, and resolved itself after a few minutes. But if you’re experiencing this error message, check your L2/L3 connection. Also, verify DNS is working and someone didn’t make changes to your firewall(s). Just walk up or down the OSI model and you’ll eventually find the problem.</p> - + http://localhost:1313/posts/2018-07-26-azure-ad-connect-no-start-connection/ + This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working. After forcing the sync, I opened miisclient and noticed some strange errors. - Azure AD Connect Health: Latest Data is not Available in Azure Portal - https://rnemeth90.github.io/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ + http://localhost:1313/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ Wed, 18 Jul 2018 16:38:00 +0000 - - https://rnemeth90.github.io/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ - <p>I recently had to create a new Azure AD Connect server, and found that it was not able to report health status in the Azure Portal. After some troubleshooting/research, I was able to get the health status report working by registering the health agent on the server with Azure AD Health Services. Doing this involves running one PowerShell cmdlet on your AD Connect server and providing global administrator credentials.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_56.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_56.png" alt=""></a></p> -<p>First, let’s test the status of the agent communication:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_19.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_19.png" alt=""></a></p> -<p>If you do not receive any errors, that means the Azure AD Connect Health agent on your server is able to successfully communicate with the cloud service. Now, let’s register the agent:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_05.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_05.png" alt=""></a></p> -<p>You will be prompted for credentials. The credentials you provide need to be a global administrator account in your Azure AD tenant.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_42.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_42.png" alt=""></a></p> -<p>You should receive some output stating that the registration is successful (or it failed).</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h25_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h25_20.png" alt=""></a></p> -<p>Now, just go back to the Azure Portal and refresh the page. The message stating that the -“latest data is not available” should be gone.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h36_42.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h36_42.png" alt=""></a></p> - + http://localhost:1313/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ + I recently had to create a new Azure AD Connect server, and found that it was not able to report health status in the Azure Portal. After some troubleshooting/research, I was able to get the health status report working by registering the health agent on the server with Azure AD Health Services. Doing this involves running one PowerShell cmdlet on your AD Connect server and providing global administrator credentials. First, let’s test the status of the agent communication: - Removing a Forest from Azure AD Connect - https://rnemeth90.github.io/posts/2018-07-13-removing-forest-from-azure-ad-connect/ + http://localhost:1313/posts/2018-07-13-removing-forest-from-azure-ad-connect/ Fri, 13 Jul 2018 15:30:00 +0000 - - https://rnemeth90.github.io/posts/2018-07-13-removing-forest-from-azure-ad-connect/ - <p>In an organization with multiple Active Directory forests, you may want to sync objects from trusted forests. Adding trusted forests to Azure AD Sync is a simple process that I will likely cover in a future article. The focus of this post is the not-so-obvious process of removing a forest from Azure AD Connect. This can be a daunting and somewhat scary thing to do. Not fully understanding the process or having someone to guide you can leave you with thoughts like “what happens when I remove the forest from Azure AD Sync? Do on-premises objects get deleted? Are cloud objects deleted?”. I will try to answer these questions to the best of my ability and hopefully make the process simple and stress-free for you.</p> -<p>To get started, we first need to open PowerShell and disable the AD Sync scheduler. You can do this by running the “Set-ADSyncScheduler” cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h47_05.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h47_05.png" alt=""></a></p> -<p>This cmdlet is included in the ADSync PowerShell module. You may need to load the module prior to using the cmdlet:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Import-Module ADSync -</span></span></code></pre></div><p>The next step is to open FIM (miisclient) located in the install directory of Microsoft Azure AD Sync. By default, this is C:Program FilesMicrosoft Azure AD SyncUIShellmiisclient.exe. Once you have FIM open, click on the Connectors tab, then right click on the connector for the forest that you want to delete, and click “Delete”.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_26.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_26.png" alt=""></a></p> -<p>You will then be prompted, asking if you want to just delete the Connector Space, or delete the Connector and the Connector Space. The former open removes all data, but keeps the configuration in case you want to use it again later. The latter option deleted the data and the configuration. This open should only be used if you don’t plan on syncing the forest again.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_09.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_09.png" alt=""></a></p> -<p>The connector for the forest is now deleted, but what actually happens? Your on-premises objects do not get removed for the forest, and cloud objects <strong>are</strong> removed. Simple enough, right?</p> -<p>Now you just need to re-enable the AD Sync Scheduler with this cmdlet:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Set-ADSyncScheduler -SyncCycleEnabled $true -</span></span></code></pre></div><p>One last thing to mention… You may receive an email from the Microsoft Online Services Team stating that the identity synchronization failed due to a deletion threshold being met. By default, Azure AD Connect will not allow you to delete more than 500 objects in your cloud directory. This is to protect you from making a careless (potentially resume generating) mistake. The email will look something like this:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h56_04.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h56_04.png" alt=""></a></p> -<p>If you are certain that you want to proceed with deleting the objects, here are the steps:</p> -<ol> -<li> -<p>Disable the deletion threshold protection. Open PowerShell on your Azure AD Sync server and type in this cmdlet: Disable-ADSyncExportDeletionThreshold. You will be prompted for credentials, sign-in with an Azure AD Global Admin account.</p> -</li> -<li> -<p>Open FIM (miisclient), and click on the “Connectors” button at the top of the window. Right click on the connector of type “Windows Azure Active Directory”, and select “Run…”.</p> -</li> -</ol> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_39.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_39.png" alt=""></a></p> -<ol start="3"> -<li>Next, click Export and then click Ok.</li> -</ol> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_58.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_58.png" alt=""></a></p> -<ol start="4"> -<li> -<p>Allow the connector to run. This will take a few minutes. You can monitor the progress by clicking the Operations button.</p> -</li> -<li> -<p>Once this completes, you need to re-enable the deletion threshold. You can do this by running this cmdlet: <span style="background: #F9F9F9;"></p> -</li> -</ol> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Enable-ADSyncExportDeletionThreshold -DeletionThreshold <span style="color:#ae81ff">500</span>. -</span></span></code></pre></div><p>You will be prompted for credentials again. Just type in your Azure AD Global Admin creds. You can even lower the threshold if you’d like. I set mine to 100.</p> - + http://localhost:1313/posts/2018-07-13-removing-forest-from-azure-ad-connect/ + In an organization with multiple Active Directory forests, you may want to sync objects from trusted forests. Adding trusted forests to Azure AD Sync is a simple process that I will likely cover in a future article. The focus of this post is the not-so-obvious process of removing a forest from Azure AD Connect. This can be a daunting and somewhat scary thing to do. Not fully understanding the process or having someone to guide you can leave you with thoughts like “what happens when I remove the forest from Azure AD Sync? - Access is Denied When Attempting to Delete a Dynamic Distribution Group - https://rnemeth90.github.io/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ + http://localhost:1313/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ Mon, 12 Jun 2017 13:41:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ - <p>You may receive the error below when attempting to delete a dynamic distribution group.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-12_09h29_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-12_09h29_20.png" alt=""></a></p> -<p>To resolve this, open ADUC and show advanced features (Click View &gt; Advanced Features). Then find the object for the dynamic distribution group and open the properties window. Browse to the “Object” tab and uncheck the “Protect object from accidental deletion” box. Wait for ADDS to replicate or force replication yourself.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-12_09h34_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-12_09h34_20.png" alt=""></a></p> -<p>Go back to the ECP and you should be able to delete the group.</p> - + http://localhost:1313/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ + You may receive the error below when attempting to delete a dynamic distribution group. To resolve this, open ADUC and show advanced features (Click View &gt; Advanced Features). Then find the object for the dynamic distribution group and open the properties window. Browse to the “Object” tab and uncheck the “Protect object from accidental deletion” box. Wait for ADDS to replicate or force replication yourself. Go back to the ECP and you should be able to delete the group. - The User Profile Service service failed the logon - https://rnemeth90.github.io/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ + http://localhost:1313/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ Wed, 30 Dec 2015 10:38:00 +0000 - - https://rnemeth90.github.io/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ - <p>One of my clients had a really strange issue the other day. He has a domain admin account in his domain and was not able to login to a server that I recently built. The server was an Exchange 2013 box, and was used in Coexistence mode to migrate his company from an Exchange 2007 box.</p> -<p>He was getting this error message when attempting to login:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/12/2015-12-30_09h38_53.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/12/2015-12-30_09h38_53.png" alt=""></a></p> -<p>This is a classic error message that I’m sure most technicians have seen before. Usually the resolution is to go into the registry and rename the user profile key to have a “.bak” extension and then do some other magic. However, this time, that was not the case. I looked in the registry and didn’t even see a reg key for his profile. I then looked in the c:users folder and didn’t see a folder for his profile. Strange…</p> -<p>So what exactly was happening? Well, I took a look at the Event Viewer and found this error message:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/12/2015-12-30_09h34_06.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/12/2015-12-30_09h34_06.png" alt=""></a></p> -<p>I browsed to the file referenced in the error message and deleted it. Walla! He was able to login with his admin account. I’m not sure why this file was in the default user profile. It has something to do with Customer Experience Improvement Program:</p> -<p><a href="http://www.nextofwindows.com/what-is-sqmdata-and-sqm-file-in-windows-7-and-how-to-delete-them">http://www.nextofwindows.com/what-is-sqmdata-and-sqm-file-in-windows-7-and-how-to-delete-them</a></p> - + http://localhost:1313/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ + One of my clients had a really strange issue the other day. He has a domain admin account in his domain and was not able to login to a server that I recently built. The server was an Exchange 2013 box, and was used in Coexistence mode to migrate his company from an Exchange 2007 box. He was getting this error message when attempting to login: This is a classic error message that I’m sure most technicians have seen before. - Script for Querying All AD Computers Time Source - https://rnemeth90.github.io/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ + http://localhost:1313/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ Tue, 01 Sep 2015 21:05:00 +0000 - - https://rnemeth90.github.io/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ - <p>This script will iterate through all computers in Active Directory and return the configured time server for each computer.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span><span style="color:#75715e">&lt;# -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">SYNOPSIS</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Get time source for all computers in domain -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">EXAMPLE</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Get-TimeSource -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">NOTES</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Author: Ryan Nemeth - RyanNemeth@live.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Site: http://www.geekyryan.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">LINK</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> http://www.geekyryan.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">DESCRIPTION</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> This function will iterate through all computers/servers in a domain and return the time source -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> for each. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#&gt;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Write-Host -foregroundcolor Red -BackgroundColor black <span style="color:#e6db74">&#34;This script must be run on a domain controller and requires that the AD Powershell module be installed&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$module = Get-Module -ListAvailable | Select-Object -ExpandProperty Name -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span>($module <span style="color:#f92672">-notcontains</span> <span style="color:#e6db74">&#34;ActiveDirectory&#34;</span>) { -</span></span><span style="display:flex;"><span> Write-Host -foregroundcolor red -backgroundcolor black <span style="color:#e6db74">&#34;***Active Directory Powershell Module Not Found***&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span> { -</span></span><span style="display:flex;"><span> Write-Host -foregroundcolor yellow <span style="color:#e6db74">&#34;Found Active Directory Powershell Module. Importing...&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Import-Module ActiveDirectory -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$computers = get-adcomputer -filter * | Select-Object -ExpandProperty Name -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span>($computer <span style="color:#66d9ef">in</span> $computers) { -</span></span><span style="display:flex;"><span> $tm_source = w32tm /query /computer<span style="color:#960050;background-color:#1e0010">:</span>$computer /source -</span></span><span style="display:flex;"><span> write-host <span style="color:#e6db74">&#34;The time source for&#34;</span> $computer <span style="color:#e6db74">&#34;is&#34;</span> $tm_source -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><img src="https://github.com/rnemeth90/PowerShell/blob/master/NTP/Get-TimeSource.ps1" alt=""></p> - + http://localhost:1313/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ + This script will iterate through all computers in Active Directory and return the configured time server for each computer. &lt;# .SYNOPSIS Get time source for all computers in domain .EXAMPLE Get-TimeSource .NOTES Author: Ryan Nemeth - RyanNemeth@live.com Site: http://www.geekyryan.com .LINK http://www.geekyryan.com .DESCRIPTION This function will iterate through all computers/servers in a domain and return the time source for each. #&gt; Write-Host -foregroundcolor Red -BackgroundColor black &#34;This script must be run on a domain controller and requires that the AD Powershell module be installed&#34; $module = Get-Module -ListAvailable | Select-Object -ExpandProperty Name if($module -notcontains &#34;ActiveDirectory&#34;) { Write-Host -foregroundcolor red -backgroundcolor black &#34;***Active Directory Powershell Module Not Found***&#34; } else { Write-Host -foregroundcolor yellow &#34;Found Active Directory Powershell Module. - Powershell: SID to Username - https://rnemeth90.github.io/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ + http://localhost:1313/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ Mon, 08 Dec 2014 13:43:00 +0000 - - https://rnemeth90.github.io/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ - <p>This is a simple script to convert a SID to a username</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span><span style="color:#75715e"># Returns a username based on a SID</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Author: Ryan Nemeth</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Date: 12/2/2014</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$SID = read-host <span style="color:#960050;background-color:#1e0010">“</span>Please enter the SID<span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#960050;background-color:#1e0010">”</span> -</span></span><span style="display:flex;"><span>$object = New-Object System.Security.Principal.SecurityIdentifier($SID) -</span></span><span style="display:flex;"><span>$User = $object.Translate( \[System.Security.Principal.NTAccount\]) -</span></span><span style="display:flex;"><span>write-host <span style="color:#960050;background-color:#1e0010">“</span>The user is<span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#960050;background-color:#1e0010">”</span> $User.Value -</span></span></code></pre></div> + http://localhost:1313/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ + This is a simple script to convert a SID to a username # Returns a username based on a SID # Author: Ryan Nemeth # Date: 12/2/2014 $SID = read-host “Please enter the SID: ” $object = New-Object System.Security.Principal.SecurityIdentifier($SID) $User = $object.Translate( \[System.Security.Principal.NTAccount\]) write-host “The user is: ” $User.Value - Unlock a Domain User from CMD Line - https://rnemeth90.github.io/posts/2014-12-08-unlock-domain-user-from-cmd-line/ + http://localhost:1313/posts/2014-12-08-unlock-domain-user-from-cmd-line/ Mon, 08 Dec 2014 02:11:00 +0000 - - https://rnemeth90.github.io/posts/2014-12-08-unlock-domain-user-from-cmd-line/ - <p>To unlock a domain user from the command line, use this command:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>net user &amp;lt;username&amp;gt; /domain /active:yes -</span></span></code></pre></div><p>This can also be done using Powershell:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Unlock-ADAccount -identity <span style="color:#960050;background-color:#1e0010">“</span>CN=John,OU=myUsers,DC=myDomain,DC=local<span style="color:#960050;background-color:#1e0010">”</span> -</span></span></code></pre></div> + http://localhost:1313/posts/2014-12-08-unlock-domain-user-from-cmd-line/ + To unlock a domain user from the command line, use this command: net user &amp;lt;username&amp;gt; /domain /active:yes This can also be done using Powershell: Unlock-ADAccount -identity “CN=John,OU=myUsers,DC=myDomain,DC=local” - The Case of Transitive Trusts and Dropped RPC Connections - https://rnemeth90.github.io/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ + http://localhost:1313/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ Tue, 25 Nov 2014 01:27:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ - <p>I was at a client earlier this morning, working to get a transitive forest trust setup between their two domains. Setting up the trust on ServerA to DomainB went without issue. However, when trying to create the trust between ServerB and DomainA, I received this error: The secure channel reset on Active Directory Domain Controller (Your domain controller) of domain (Your domain) to domain (your other domain) failed with error: RPC server is unavailable.</p> -<p>Troubleshooting (as always) started off with the basics: is the firewall on or off, are the services running, are the names being properly resolved, etc. Well, the Windows Firewall on both servers was off and -the RPC services were running. So what now?? I fired up NMAP on ServerB and did a syn scan on ServerA. After reviewing the output, I could see that the ports were open. I then went over to ServerA and opened up the Services MSC console. The RPC services appeared to be running. Being that they are system services and you cannot manually interact with them, I was unable to manually restart them. Just out of curiosity,</p> -<p>I opened a command prompt while connected to that server and ran Netstat -A. This is when I had the “AHA!” moment. Nothing was listening on any of the RPC ports! I rebooted the server (something I don’t really like to do..), logged in and ran Netstat -A again. This time, RPC was listening. I went back over to ServerB, walked through the New Trust Wizard, and success! Oh, the feeling of victory!</p> - + http://localhost:1313/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ + I was at a client earlier this morning, working to get a transitive forest trust setup between their two domains. Setting up the trust on ServerA to DomainB went without issue. However, when trying to create the trust between ServerB and DomainA, I received this error: The secure channel reset on Active Directory Domain Controller (Your domain controller) of domain (Your domain) to domain (your other domain) failed with error: RPC server is unavailable. - diff --git a/public/tags/activedirectory/page/1/index.html b/public/tags/activedirectory/page/1/index.html index fa51ac21..74ccde1a 100644 --- a/public/tags/activedirectory/page/1/index.html +++ b/public/tags/activedirectory/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/activedirectory/ - + http://localhost:1313/tags/activedirectory/ + - + diff --git a/public/tags/activedirectory/page/2/index.html b/public/tags/activedirectory/page/2/index.html index adb4fd00..07b3a641 100644 --- a/public/tags/activedirectory/page/2/index.html +++ b/public/tags/activedirectory/page/2/index.html @@ -1,112 +1,77 @@ + - - - - - - - + + Tag: ActiveDirectory · GeekyRyan + - - -ActiveDirectory - GeekyRyan - - - - - - - - - - + - - + + + - - + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - + + + + + + + - - - - - - - - - + @@ -114,355 +79,192 @@ - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - + - -
    -
    - -

    Tag: ActiveDirectory

    - +
      + +
    • «
    • -
      -
      -
      -

      Unlock a Domain User from CMD Line

      -
      - -
      - + + + -
      - To unlock a domain user from the command line, use this command: -net user &lt;username&gt; /domain /active:yes This can also be done using Powershell: -Unlock-ADAccount -identity “CN=John,OU=myUsers,DC=myDomain,DC=local” -
      + + +
    • 1
    • + - + - - -
    - https://rnemeth90.github.io/posts/2014-12-08-unlock-domain-user-from-cmd-line/ - Ryan + -
    - - - - - - -
    -
    - - -
    -
    -
    -

    The Case of Transitive Trusts and Dropped RPC Connections

    -
    -
    +
    +
    + © -
    - I was at a client earlier this morning, working to get a transitive forest trust setup between their two domains. Setting up the trust on ServerA to DomainB went without issue. However, when trying to create the trust between ServerB and DomainA, I received this error: The secure channel reset on Active Directory Domain Controller (Your domain controller) of domain (Your domain) to domain (your other domain) failed with error: RPC server is unavailable. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - + + - -
    - - - - - + + + - - -
    - - + - + -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + + + + + diff --git a/public/tags/aks/index.html b/public/tags/aks/index.html index 6b2f443f..6dea520d 100644 --- a/public/tags/aks/index.html +++ b/public/tags/aks/index.html @@ -1,849 +1,264 @@ + - - - - - - - + + Tag: Aks · GeekyRyan + - + -aks - GeekyRyan - + + + - - - + + + + + + + + + - - - - + + + + + + + - - - - - - - - - + - + + + - - - - - - - - - - + + + + + + + - - - - + - - - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - -
    -
    - -

    Tag: aks

    - - - -
    -
    -
    -

    AKS Scale Down Mode

    -
    - -
    - - -
    - By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete or deallocate nodes. -Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Scheduled Kubernetes Worker Node Maintenance with Kured

    -
    - -
    - - -
    - If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this? -Weaveworks created a great tool for simplifying these steps: Kured (the Kubernetes Reboot Daemon). -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Running Docker in WSL v1

    -
    - -
    - - -
    - I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. -Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Remove Kubernetes Namespace Stuck in the Terminating State

    -
    - -
    - - -
    - In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state. -A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. -
    - - -
    - Read more -
    - - - - - - - -
    - -
    -
    -
    -

    Kubernetes Storage Simplified

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Tag: Aks +

    +
    + +
    +
  • + 2022-01-16 + Azure Kubernetes sFTP Solution +
  • -
    -
    -
    -

    Kubernetes Pod Eviction

    -
    - -
    + + - -
    - In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation. -What is Pod Eviction? Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Azure Kubernetes sFTP Solution

    -
    -
    +
    +
    + © -
    - In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault. -Here is the link to my Github account where you can download the code mentioned in this article: -https://github.com/rnemeth90/kubernetes-sftp -We will work through the following steps in this article: -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/aks/index.xml b/public/tags/aks/index.xml index a71cdb1b..f500826b 100644 --- a/public/tags/aks/index.xml +++ b/public/tags/aks/index.xml @@ -1,643 +1,61 @@ - aks on GeekyRyan - https://rnemeth90.github.io/tags/aks/ - GeekyRyan (aks) - Hugo -- gohugo.io - en-us + Aks on GeekyRyan + http://localhost:1313/tags/aks/ + Recent content in Aks on GeekyRyan + Hugo + en Tue, 19 Jul 2022 00:00:00 +0000 - - - - + AKS Scale Down Mode - https://rnemeth90.github.io/posts/2022-07-19-aks-scale-down-mode/ + http://localhost:1313/posts/2022-07-19-aks-scale-down-mode/ Tue, 19 Jul 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-07-19-aks-scale-down-mode/ - <p>By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete <em>or</em> deallocate nodes.</p> -<p>Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. However, you will still need to pay for any storage that the node is using. Having persistent storage also means that any container images that were cached on the node will still be there when the node starts back up. This can be a major performance benefit if you are using Windows containers because the images for these containers are typically very large.</p> -<p>Scale down mode can be configured in several ways. Here, we will look at configuring it via the Azure CLI and Terraform.</p> -<p>Azure CLI:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>az aks nodepool update --scale-down-mode Deallocate --name nplinux01 --cluster-name myAKSCluster --resource-group myResourceGroup -</span></span></code></pre></div><p>Terraform:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-hcl" data-lang="hcl"><span style="display:flex;"><span><span style="color:#66d9ef">resource</span> <span style="color:#e6db74">&#34;azurerm_kubernetes_cluster_node_pool&#34; &#34;nodepool&#34;</span> { -</span></span><span style="display:flex;"><span> name <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;nplinux01&#34;</span> -</span></span><span style="display:flex;"><span> kubernetes_cluster_id <span style="color:#f92672">=</span> <span style="color:#66d9ef">azurerm_kubernetes_cluster</span>.<span style="color:#66d9ef">example</span>.<span style="color:#66d9ef">id</span> -</span></span><span style="display:flex;"><span> vm_size <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Standard_DS2_v2&#34;</span> -</span></span><span style="display:flex;"><span> node_count <span style="color:#f92672">=</span> <span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span> scale_down_mode <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Deallocate&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> tags <span style="color:#f92672">=</span> { -</span></span><span style="display:flex;"><span> Environment <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;lab&#34;</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><em>At the time of this writing, Terraform does not support configuring scale-down mode for the default AKS node pool.</em> -<em>Node pools using ephemeral disks do not support &lsquo;deallocate&rsquo; mode</em></p> - + http://localhost:1313/posts/2022-07-19-aks-scale-down-mode/ + By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete or deallocate nodes. Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. - Scheduled Kubernetes Worker Node Maintenance with Kured - https://rnemeth90.github.io/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ + http://localhost:1313/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ Fri, 15 Jul 2022 18:18:50 +0000 - - https://rnemeth90.github.io/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ - <p>If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this?</p> -<p>Weaveworks created a great tool for simplifying these steps: Kured (the <em><strong>Ku</strong>bernetes <strong>Re</strong>boot <strong>D</strong>aemon</em>). Let’s start by deploying Kured to our cluster.</p> -<p>Kured can be deployed in one of several ways. In this article, we’ll focus on deploying it via Helm. This is the simplest and quickest way to get it running in our cluster.</p> -<p>Follow these steps to install the Helm chart:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># 1) Add the Kured Helm repository</span> -</span></span><span style="display:flex;"><span>helm repo add kured https://weaveworks.github.io/kured -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 2) Update your local Helm chart repository cache</span> -</span></span><span style="display:flex;"><span>helm repo update -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 3) Create a dedicated namespace where you would like to deploy kured</span> -</span></span><span style="display:flex;"><span>kubectl create namespace kured -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 4) Install kured in that namespace with Helm 3 (only on Linux nodes)</span> -</span></span><span style="display:flex;"><span>helm install kured kured/kured --namespace kured --set nodeSelector.<span style="color:#e6db74">&#34;kubernetes\.io/os&#34;</span><span style="color:#f92672">=</span>linux -</span></span></code></pre></div><p>If all went well with the command above, that’s it, you’re done! Have a nice day! 🙂</p> -<p>If you want to test Kured, login to one of your Linux nodes, and install some patches with your package manager of choice (any patch that requires a reboot, typically patches that modify kernel headers). Then, check for a file named ‘reboot-required’ in /var/run:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>ls -lisa /var/run/reboot-required -</span></span></code></pre></div><p>If you installed patches, and this file does not exist, none of your patches require a reboot. We can still fake the system into thinking a reboot is required by manually creating the ‘reboot-required’ file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo touch /var/run/reboot-required -</span></span></code></pre></div><p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-1.png" alt=""></p> -<p>Then, we’ll use Kubetail to tail the logs of all our Kured pods:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubetail -label kured --namespace kured -</span></span></code></pre></div><p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-1024x749.png" alt=""></p> -<p>By default, Kured checks for the existence of the sentinel file every 60 minutes. However, this behavior can be changed. See the github repo for more info:</p> -<p><img src="https://github.com/weaveworks/kured#reboot-sentinel-file--period" alt="weaveworks/kured: Kubernetes Reboot Daemon"></p> -<p>Scheduling on the node should be disabled if you are within the Kured schedule</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-2.png" alt=""></p> -<p>Now that the node is cordoned off, running pods on the node are drained, and the node is rebooted.</p> -<p>That’s it for this article. Have a great day!</p> - + http://localhost:1313/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ + If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this? Weaveworks created a great tool for simplifying these steps: Kured (the Kubernetes Reboot Daemon). - Running Docker in WSL v1 - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ Sun, 26 Jun 2022 15:00:28 +0000 - - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ - <p>I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate.</p> -<p>Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. I receive this nice message:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ docker -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>The command <span style="color:#e6db74">&#39;docker&#39;</span> could not be found in this WSL <span style="color:#ae81ff">1</span> distro. -</span></span><span style="display:flex;"><span>We recommend to convert this distro to WSL <span style="color:#ae81ff">2</span> and activate -</span></span><span style="display:flex;"><span>the WSL integration in Docker Desktop settings. -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>See https://docs.docker.com/docker-for-windows/wsl/ <span style="color:#66d9ef">for</span> details. -</span></span></code></pre></div><p>So I’m in somewhat of a catch-22 here…</p> -<p>To work around this problem until a proper solution is found, I was able to get Docker working with WSL v1.</p> -<p>If you happen to be having a similar issue (and it seems like quite a few people are, considering the number of Github posts I found), just follow these steps:</p> -<ul> -<li>Expose the Docker daemon in docker desktop settings:</li> -</ul> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/02/image-10-1024x585.png"></a></p> -<p>Install the stand-alone Docker client in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ tar zxvf docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ cd docker -</span></span></code></pre></div><p>Set the default Docker daemon in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>export DOCKER_HOST<span style="color:#f92672">=</span>tcp://localhost:2375 -</span></span></code></pre></div><p>Verify you can connect to Docker running on Windows from within WSL:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>./docker info -</span></span></code></pre></div><p>This is also beneficial in that you only have one Docker host to manage your containers, network, etc., rather than two.</p> - + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ + I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. - Remove Kubernetes Namespace Stuck in the Terminating State - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ Sat, 04 Jun 2022 18:29:41 +0000 - - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ - <p>In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state.</p> -<p>A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. One day, you decide you no longer want this blog, so you plan to delete it. Rather than tediously deleting all of the various entities associated with this blog, you can delete the namespace that contains these entities. This will essentially ‘cascade delete’ the resources within the namespace as well.</p> -<p>After deleting the namespace for your blog, you notice that it still exists, but the state of it is ‘Terminating’, and it has been like this for a long time (hours or maybe even days).</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/06/image.png"></a></p> -<p>Kubernetes will occassionally fail to delete third-party resources when deleting a namespace, causing the namespace to linger. This can happen if the third-party API managing the resource is not responding to requests. To verify if any of these resources still exist, use this command:</p> -<pre tabindex="0"><code>kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get --show-kind --show-all --ignore-not-found -n &lt;terminating-namespace&gt; -</code></pre><p>If you happen to see any resources in the output, you can try force deleting them and then try to delete the namespace again.</p> -<p>In my experience, the majority of the time you will not find any resources still hanging around. Rather, the namespace will be completely empty. What is going on here?</p> -<p>Let’s take a look at the namespace:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ae81ff">$ kubectl get namespace darn-c101 -o yaml</span> -</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Namespace</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">annotations</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">kubectl.kubernetes.io/last-applied-configuration</span>: <span style="color:#ae81ff">|</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">kubernetes.io/metadata.name</span>: <span style="color:#ae81ff">darn-c101</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">finalizers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">kubernetes</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">status</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">conditions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">lastTransitionTime</span>: <span style="color:#e6db74">&#34;2022-06-01T19:05:31Z&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">message: &#39;Some content in the namespace has finalizers remaining</span>: <span style="color:#ae81ff">darn-c101.geekyryan.io/finalizer in 1 resource instances&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">reason</span>: <span style="color:#ae81ff">SomeFinalizersRemain</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">status</span>: <span style="color:#e6db74">&#34;True&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">NamespaceFinalizersRemaining</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">phase</span>: <span style="color:#ae81ff">Terminating</span> -</span></span></code></pre></div><p>Notice the inclusion of the finalizers field in the above JSON. Some namespaces have a finalizer defined under spec.</p> -<p>A finalizer is a special metadata key that tells Kubernetes to wait until a specific condition is met before it fully deletes a resource. Much like a finalizer in the .NET framework (does Java have those too? 😀 )</p> -<p>So when you run a command like <code>kubectl delete namespace &lt;namespace&gt;</code>, Kubernetes checks for a finalizer in the <code>metadata.finalizers</code> field. If the resource defined in the finalizer cannot be deleted, then the namespace is not deleted either. This puts the namespace into a perpetual terminating state and is never actually deleted.</p> -<p>When an object has been terminating for an excessive time, check its finalizers by inspecting the <code>metadata.finalizers</code> field in its YAML.</p> -<p>So we now know what the problem is. How can we solve it? Well, it’s actually quite simple. If you are using bash, use this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> -</span></span><span style="display:flex;"><span>namespaces<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>kubectl get ns --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Terminating -o jsonpath<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;{range .items[*]}{.metadata.name}{&#34;\n&#34;}{end}&#39;</span><span style="color:#66d9ef">)</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -z <span style="color:#e6db74">&#34;</span>$namespaces<span style="color:#e6db74">&#34;</span><span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">&#34;No namespaces to delete.&#34;</span> -</span></span><span style="display:flex;"><span> exit -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> namespace in $namespaces -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">do</span> -</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">&#34;[Removing Namespace]: </span>$namespace<span style="color:#e6db74">&#34;</span> -</span></span><span style="display:flex;"><span> kubectl get namespace $namespace -o json | tr -d <span style="color:#e6db74">&#34;\n&#34;</span> | sed <span style="color:#e6db74">&#34;s/\&#34;finalizers\&#34;: \[[^]]\+\]/\&#34;finalizers\&#34;: []/&#34;</span> | kubectl replace --raw /api/v1/namespaces/$namespace/finalize -f - &gt; /dev/null 2&gt;&amp;<span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">done</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span> -</span></span></code></pre></div><p><a href="https://gist.github.com/rnemeth90/e83bb4c8808f0d28412cb40edb2487d3">Delete Terminating Kubernetes Namespaces with Bash (github.com)</a></p> -<p>It will search for any namespace that is stuck in the terminating state and forcefully remove it by removing the finalizers field and then using <code> kubectl replace</code> to commit the change back to the Kube API.</p> -<p>If you prefer Powershell, you can use this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$terminatingNamespaces = kubectl get ns --field-selector=status.phase==Terminating -o jsonpath=<span style="color:#e6db74">&#34;{range .items[*]}{.metadata.name}{&#39;\n&#39;}{end}&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($ns <span style="color:#66d9ef">in</span> $terminatingNamespaces) { -</span></span><span style="display:flex;"><span> Write-Verbose <span style="color:#e6db74">&#39;[FOUND]: Forcefully removing $ns&#39;</span> -</span></span><span style="display:flex;"><span> $jsonObj = kubectl get namespace $ns -o json | ConvertFrom-Json | foreach-object { $_.spec.finalizers = @(); $_ } | -</span></span><span style="display:flex;"><span> convertto-json | kubectl replace --raw /api/v1/namespaces/$namespace/finalize <span style="color:#f92672">-f</span> - -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><a href="https://gist.github.com/rnemeth90/19d7de622a5009c1cf908c5d4deb5358">Delete Terminating Kubernetes Namespaces with Powershell (github.com)</a></p> -<p>It does the same thing as the bash script, just in more of a Window-zy way.</p> -<p>It’s that simple. I hope this was helpful. If you have any questions, comments, or concerns, please feel free to reach out.</p> - + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state. A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. - Kubernetes Storage Simplified - https://rnemeth90.github.io/posts/2022-03-01-kubernetes-storage-simplified/ + http://localhost:1313/posts/2022-03-01-kubernetes-storage-simplified/ Tue, 01 Mar 2022 08:37:58 +0000 - - https://rnemeth90.github.io/posts/2022-03-01-kubernetes-storage-simplified/ - <p>In this blog post, we will attempt to explain the current storage options that exist in Kubernetes. If you are new to Kubernetes, learning about its capabilities of managing the application state can be a daunting task.</p> -<p>Container images are built-in layers, with the runtime layer being writable. However, any files on this writable layer are only available for the container’s lifetime. We can mount a volume to a directory inside the container to have persistent data.</p> -<p>Kubernetes storage uses the concepts of volumes. Ephemeral volumes are called volumes and only last the lifetime of a pod, and “persistent volumes” are used for long-term storage. A typical use case for Ephemeral volumes is storing logs that are not sent to stdout.</p> -<p>Mounting a persistent volume inside a container allows you to persist the state of your application long after the container is terminated. Persistent volumes can also take advantage of the typical storage idiosyncrasies such as backup, compression, and encryption.</p> -<h2 id="persistent-volumes" >Persistent Volumes -<span> - <a href="#persistent-volumes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Kubernetes has several types of persistent volumes. At its core, a persistent volume is simply a directory mounted inside a pod. How that volume is created, the configuration options and the medium that backs it are all determined by the type of volume created.</p> -<p>There are several types of volumes available, too many to list here. You may commonly see some volume types: NFS, iSCSI, hostpath, and local. If your Kubernetes cluster exists in a cloud environment such as Azure or AWS, other volume types are available to you (azureDisk, azureFile, and awsElasticBlockStore, respectively). A complete list of types can be found here:</p> -<p><a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes">https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes</a></p> -<p>Creating a persistent volume is generally a simple task. The first step is determining the type of volume to create. In this post, we will cover creating a local volume. A local volume represents a disk, partition, or directory shared from a node. Local volumes are subject to the availability of the underlying node, meaning that if the node is offline, the volume is also offline and will not be accessible by any pod. Because of this, local volumes should not be used in production.</p> -<p>A persistent volume can only be created using a declarative approach. To create a persistent local volume, use the following YAML definition:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolume</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">example-pv</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">capacity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMode</span>: <span style="color:#ae81ff">Filesystem</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteOnce</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeReclaimPolicy</span>: <span style="color:#ae81ff">Delete</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">local-storage</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">local</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># the path to the volume or directory on the node</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/mnt/disks/ssd1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeAffinity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">required</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeSelectorTerms</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">matchExpressions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">key</span>: <span style="color:#ae81ff">kubernetes.io/hostname</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">operator</span>: <span style="color:#ae81ff">In</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">values</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># name of the node sharing the volume</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">node01</span> -</span></span></code></pre></div><p>When creating a persistent volume of this type, you must specify a node affinity. This ensures that the Kubernetes scheduler schedules any pods requesting access to this volume on the correct node. For example, any pod requesting access to the persistent volume named ‘example-PV will only be scheduled on the node ‘node01’.</p> -<p>Let’s dive into this persistent volume spec a bit more:</p> -<p>You can change the capacity of the persistent volume by updating:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">capacity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span></code></pre></div><p>The accessModes will be determined by the storage provider being used. There are generally 3 access modes available: ReadWriteOnce, ReadWriteMany, and ReadOnlyMany.</p> -<ul> -<li>ReadWriteOnce – The volume can be mounted as read-write by a single node</li> -<li>ReadWriteMany – The volume can be mounted as read-write by many nodes</li> -<li>ReadOnlyMany – The volume can be mounted as read-only by many nodes</li> -</ul> -<p>The “persistentVolumeReclaim” policy determines what happens to a persistent volume when it is no longer mounted by any pods (i.e., there are no claims to it, more on this later). There are three options available for the reclaim policy:</p> -<ul> -<li>Retain – The persistent volume is kept as-is. It must be manually removed when no longer needed.</li> -<li>Recycle – The persistent volume is scrubbed and can be re-used by other pods</li> -<li>Delete – The persistent volume is deleted.</li> -</ul> -<p>Currently, only NFS and hostPath volumes support recycling. Cloud storage providers (Azure, AWS, and GCE) support deletion.</p> -<p>The other aspects of this spec are unique to the volume being used. Since we are using a local volume here, we must specify the path to the directory or volume on the host and the host which is sharing the directory or volume:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span> <span style="color:#f92672">local</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># the path to the volume or directory on the node</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/mnt/disks/ssd1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeAffinity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">required</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeSelectorTerms</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">matchExpressions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">key</span>: <span style="color:#ae81ff">kubernetes.io/hostname</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">operator</span>: <span style="color:#ae81ff">In</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">values</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># name of the node sharing the volume</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">node01</span> -</span></span></code></pre></div><h2 id="ephemeral-volumes" >Ephemeral Volumes -<span> - <a href="#ephemeral-volumes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Note: The Kubernetes documentation recognizes configMaps and Secrets as ephemeral volumes. However, in this article, we will only discuss ephemeral volumes used for data storage (emptyDir volumes).</p> -<p>Ephemeral volumes are defined within the context of a pod. This means that you cannot create an ephemeral volume on its own. Instead, define the ephemeral volume in the pod or a deployment spec.</p> -<p>Ephemeral volumes are useful in a few scenarios:</p> -<ol> -<li>You want to share data between multiple containers in a pod</li> -<li>You want to cache temporary information such as log files</li> -<li>You need scratch space to store data before it is processed by another container or pod</li> -</ol> -<p>If one of the containers in the pod happens to restart, data on the ephemeral volume will still exist; as long as one of the containers is mounting, it stays online. In other words, if a pod mounting the ephemeral volume is removed from a node, data on the ephemeral volume is lost. However, if a pod crashes, the data on the volume remains intact.</p> -<p>As stated previously, creating an ephemeral volume is done as part of the pod or deployment template:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/cache</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">emptyDir</span>: {} -</span></span></code></pre></div><p>If the template, you add a volume of type ’emptyDir’ in the ‘volumes’ spec and name it. You can mount this volume in any container in the pod. The volume does not have to be mounted to the same directory in each container.</p> -<h2 id="persistent-volume-claims" >Persistent Volume Claims -<span> - <a href="#persistent-volume-claims"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>A persistentVolumeClaim (often referred to as a ‘PVC’) is used by a pod to create a ‘claim’ on storage. Using a PVC, a pod can mount multiple persistent volumes simultaneously to any directory in the pod.</p> -<p>PersistentVolumeClaim’s are a Kubernetes primitive that can be deployed from a manifest:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fast-storage-pvc</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMode</span>: <span style="color:#ae81ff">Filesystem</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">8Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">fast</span> -</span></span></code></pre></div><p>Most of the options in the manifest above seem pretty obvious. The volumeMode specifies whether to consume the persistent volume as a FileSystem or block device. The resources section helps specify the amount of storage you require (8Gi in this example). We will cover the storageClassName in the next section. Finally, the accessModes are identical to those described above in the Persistent Volumes section.</p> -<p>Pods access a volume by using the persistentVolumeClaim as volume. Claims must exist in the same namespace as the pod using the claim. The controller finds the claim in the pods’ namespace and uses it to find a persistent volume capable of backing the claim. The volume is then mounted on the host and attached to the pod.</p> -<p>To create a pod that utilizes a PVC, use the following yaml definition:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/mnt/share</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span></code></pre></div><h2 id="storage-classes" >Storage Classes -<span> - <a href="#storage-classes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>In this article, we will only be referencing Kubernetes storage classes with respect to dynamic provisioners. If you would like to learn more, please reference the Kubernetes docs:</p> -<p><a href="https://bit.ly/3ruJD2A">https://bit.ly/3ruJD2A</a></p> -<p>Storage Classes have many uses. Kubernetes is unopinionated about what a storage class represents. They can be used to represent different characteristics of storage (performance, compression method, file system modes, etc.). Storage Classes can also be used to provision persistent volumes dynamically, which will be the focus of this article.</p> -<p>Storage classes are often packaged with CSI drivers. Each StorageClass contains the fields “provisioner”, “parameters”, and “reclaimPolicy”. The provisioner field is used to determine what CSI driver is used for provisioning volumes.</p> -<p>This is an example of the storage class packaged with the AzureFiles CSI driver:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">StorageClass</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">storage.k8s.io/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azurefileshare</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">provisioner</span>: <span style="color:#ae81ff">file.csi.azure.com</span> <span style="color:#75715e"># replace with &#34;kubernetes.io/azure-file&#34; if aks version is less than 1.21</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">mountOptions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">dir_mode=0777</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">file_mode=0777</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">uid=0</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">gid=0</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">mfsymlinks</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">cache=strict</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">actimeo=30</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">parameters</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">skuName</span>: <span style="color:#ae81ff">Standard_LRS</span> -</span></span></code></pre></div><p>You can see in the above manifest that the provisioner is set to ‘file.csi.azure.com.’ When a pod uses a PVC in its manifest that references this storage class, the provisioner will dynamically manage the underlying storage.</p> -<p>The name of the storageClass is referenced in the persistentVolumeClaim:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">8Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">azurefileshare</span> -</span></span></code></pre></div><p>You could then reference this PVC in a pod:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/mnt/share</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span></code></pre></div><p>That concludes this article. I know that is a lot of information! As always, if you have any questions or comments, please reach out.</p> - + http://localhost:1313/posts/2022-03-01-kubernetes-storage-simplified/ + In this blog post, we will attempt to explain the current storage options that exist in Kubernetes. If you are new to Kubernetes, learning about its capabilities of managing the application state can be a daunting task. Container images are built-in layers, with the runtime layer being writable. However, any files on this writable layer are only available for the container’s lifetime. We can mount a volume to a directory inside the container to have persistent data. - Kubernetes Pod Eviction - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ Sat, 05 Feb 2022 23:49:16 +0000 - - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ - <p>In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation.</p> -<h2 id="what-is-pod-eviction" >What is Pod Eviction? -<span> - <a href="#what-is-pod-eviction"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. The most common of which is resource starvation on a node. This is referred to as “node-pressure eviction.”</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>NAME READY STATUS RESTARTS AGE -</span></span><span style="display:flex;"><span>nginx 0/1 Evicted <span style="color:#ae81ff">0</span> 10s -</span></span></code></pre></div><h2 id="eviction-process" >Eviction Process -<span> - <a href="#eviction-process"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The kubelet process running on the node monitors resources such as CPU, memory, disk space, inodes, etc. When one of these resources reaches a certain consumption level, the kubelet will first attempt to clean up resources by deleting non-running pods and images (in the case of storage starvation). The kubelet will then fail one or more pods on the node to reclaim resources. The class of the pod determines the order in which it does this.</p> -<p><strong>Pod Classes</strong></p> -<ul> -<li>Guaranteed: Pods that have requests and limits configured for both CPU and memory</li> -<li>Burstable: Pods with a resource request configured for memory or CPU</li> -<li>Best Effort: Pods without any requests or limits</li> -</ul> -<p>The kubelet will first evict any “best-effort” pods. If this is not enough, the kubelet will evict any “burstable” pods. Pods within the “guaranteed” class are theoretically safe from eviction.</p> -<p>During a node-pressure eviction, the kubelet sets the PodPhase for the selected pods to “Failed.” This causes the pods to terminate. If a daemonSet or replicaSet manages the pod, the Kubernetes controller-manager will create new pods on another node.</p> -<h2 id="recovery" >Recovery -<span> - <a href="#recovery"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Node-pressure eviction is almost always avoidable. We can prevent this type of issue by ensuring that we properly size our clusters and create resource limits for pods.</p> -<p><strong>Resource</strong> <strong>Requests and Limits:</strong></p> -<ul> -<li>Requests: The minimum amount of resources (CPU/memory) that a container needs to start.</li> -<li>Limits: The maximum amount of resources that a container is allowed to use.</li> -</ul> -<p>Pod resources and requests can be defined in a pod spec or deployment spec. Below is an example of a pod spec with resource requests and limits defined:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">frontend</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">nginx</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;64Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;250m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">limits</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;128Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;500m&#34;</span> -</span></span></code></pre></div><p>You will often need to clean up evicted pods manually. If you find that your cluster has a large amount of evicted pods, you can clean them up with the following kubectl commands:</p> -<p><strong>To see all failed pods in the cluster:</strong></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl get pod --all-namespaces --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Failed -</span></span></code></pre></div><p><strong>To remove all failed pods in the cluster:</strong></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl delete pod --all-namespaces --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Failed -</span></span></code></pre></div><p>I hope this article has been helpful. Please reach out if you have any questions or comments! Also, if you would like to learn more, take a look at the official Kubernetes docs:</p> -<p><a href="https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/">https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/</a></p> - + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ + In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation. What is Pod Eviction? Link to heading Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. - Azure Kubernetes sFTP Solution - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ + http://localhost:1313/posts/2022-01-16-azure-kubernetes-sftp-solution/ Sun, 16 Jan 2022 07:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ - <p>In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault.</p> -<p>Here is the link to my Github account where you can download the code mentioned in this article:</p> -<p><a href="https://github.com/rnemeth90/kubernetes-sftp">https://github.com/rnemeth90/kubernetes-sftp</a></p> -<p>We will work through the following steps in this article:</p> -<ol> -<li>Deploy the AzureFile CSI driver to the AKS cluster</li> -<li>Create a configMap that our initContainer will</li> -<li>Deploy a persistent volume claim that an Azure File share will back</li> -<li>Deploy a replicaSet consisting of our initContainer and application container</li> -<li>Deploy a service to serve traffic</li> -</ol> -<p>First, you will need to deploy the Azure Files CSI driver to your AKS cluster. AKS uses this daemon set to dynamically provision/destroy Azure NFSv4 File Shares. The Azure Files CSI driver creates a storage account in the node pool resource group, in which it will then provision the file share.</p> -<p>Deploying the Azure Files CSI driver is a simple task. You will need to run this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/install-driver.sh | bash -s master -- -</span></span></code></pre></div><p>You can use the following commands to verify that the daemon set has exists:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl -n kube-system get pod -o wide --watch -l app<span style="color:#f92672">=</span>csi-azurefile-controller -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>kubectl -n kube-system get pod -o wide --watch -l app<span style="color:#f92672">=</span>csi-azurefile-node -</span></span></code></pre></div><figure class="wp-block-coblocks-gallery-masonry masonry-grid has-border-radius-10 has-medium-gutter"><figure class="wp-block-image size-large masonry-brick">[![Image gallery image](https://rnemeth90.github.io/wp-content/uploads/2022/01/image-1-1024x434.png)](https://rnemeth90.github.io/wp-content/uploads/2022/01/image-1.png)</figure></figure>Next, you need to create a storage class by deploying this yaml file: -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl create -f https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/example/storageclass-azurefile-nfs.yaml -</span></span></code></pre></div><p>Read more about the AzureFiles CSI driver at the following Github link:</p> -<p><a href="https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/install-driver-on-aks.md">https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/install-driver-on-aks.md</a></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ConfigMap</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">creationTimestamp</span>: <span style="color:#66d9ef">null</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">testcm</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">init.sh</span>: |-<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> #!/bin/bash -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> CONF_FILE=&#34;/etc/sftp/users.conf&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> KEYVAULT=&#34;Insert name of Key Vault&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_ID=&#34;Insert service principal Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_PASSWORD=&#34;Insert service principal password&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_TENANT_ID=&#34;Insert Az AAD Tenant Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SUBSCRIPTION_ID=&#34;Insert Az Subscription Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az login --service-principal --username &#34;${AZ_SPN_ID}&#34; --password &#34;${AZ_SPN_PASSWORD}&#34; --tenant &#34;${AZ_SPN_TENANT_ID}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az account set --subscription &#34;${AZ_SUBSCRIPTION_ID}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETS+=($(az keyvault secret list --vault-name $KEYVAULT --query &#34;[].id&#34; -o tsv)) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> chmod 755 /home -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [[ -e $CONF_FILE ]]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> rm -rf &#34;${CONF_FILE}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> touch $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> else -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> touch $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> for SECRET in &#34;${SECRETS[@]}&#34;; do -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETNAME=$(basename $SECRET | tr -d &#39;\r&#39;) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETVALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $SECRETNAME --query &#39;value&#39; | tr -d &#39;&#34;&#39; | tr -d &#39;\r&#39;) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;$SECRETNAME:$SECRETVALUE:::upload&#34; &gt;&gt; $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> done -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [[ ! -s $CONF_FILE ]]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;** ERROR: user.conf is empty&#34; 1&gt;&amp;2 -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> exit 1 -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi</span> -</span></span></code></pre></div><p>The initContainer will use this configMap to read secrets from an Azure Key Vault and then write the secrets to the users.conf file. The users.conf file contains user account information. In the Key Vault, the secret name should be the username and the secret value should be the password. This Key Vault must exist and contain the secrets prior to deploying this solution.</p> -<p>When I deployed this solution in my environment, I used an Azure DevOps pipeline to create/manage the Key Vault with Terraform and then deploy the secrets using an inline Powershell script. However, this is beyond the scope of this article, and I will not be covering it here. You will also need to create a Service Principal in your AAD tenant and grant it access to the Key Vault. The Service Principal needs to have at least read access to the Key Vault.</p> -<p>Before deploying the configMap, you need to fill in values for these variables:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span> KEYVAULT<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert name of Key Vault&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert service principal Id&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_PASSWORD<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert service principal password&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_TENANT_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert Az AAD Tenant Id&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SUBSCRIPTION_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert Az Subscription Id&#34;</span> -</span></span></code></pre></div><p>These values pertain to the service principal with read access to the Key Vault. After filling out these variables, you can deploy the configMap using kubectl.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl create -f configmap.yaml -</span></span></code></pre></div><p>You can deploy the PVC using this yaml file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">azurefile-csi-nfs</span> -</span></span></code></pre></div><p>When creating the persistent volume claim for the deployment, you specify azurefile-csi-nfs as the StorageClass. This will create an NFSv4 share in a premium storage account. The reclaim policy of the storage class ensures that the file share is deleted when the associated Persistent Volume is deleted. Change the reclaim policy to “Retain” if you want the file shares to persist after deleting the PV. Furthermore, the storage class enables the file share to be expandable by modifying the storage request size on the PVC.</p> -<p>After deploying the PVC, you can verify its existence by running:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl get pvc -</span></span></code></pre></div><p>You should see output similar to the following (the manifest for the replicaSet is by far the most complicated of all the code referenced here):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Deployment</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">matchLabels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">strategy</span>: {} -</span></span><span style="display:flex;"><span> <span style="color:#f92672">template</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initContainer</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">chmodder</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">mcr.microsoft.com/azure-cli</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">command</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">/bin/sh</span> -</span></span><span style="display:flex;"><span> - -<span style="color:#ae81ff">c</span> -</span></span><span style="display:flex;"><span> - <span style="color:#e6db74">&#34;/scripts/init.sh&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/scripts</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">docker.io/atmoz/sftp:alpine</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">imagePullPolicy</span>: <span style="color:#ae81ff">IfNotPresent</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;64Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;250m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">limits</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;128Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;500m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">livenessProbe</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tcpSocket</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initialDelaySeconds</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">timeoutSeconds</span>: <span style="color:#ae81ff">5</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">periodSeconds</span>: <span style="color:#ae81ff">10</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">failureThreshold</span>: <span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readinessProbe</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tcpSocket</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initialDelaySeconds</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">timeoutSeconds</span>: <span style="color:#ae81ff">5</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">periodSeconds</span>: <span style="color:#ae81ff">10</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">failureThreshold</span>: <span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/home</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/etc/sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">dnsPolicy</span>: <span style="color:#ae81ff">ClusterFirst</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">restartPolicy</span>: <span style="color:#ae81ff">Never</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">configMap</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">emptyDir</span>: {} -</span></span></code></pre></div><p>You may need to change the CPU/memory requests and limits. These values worked for me, but your results may vary. You can also add/change the labels as you see fit.</p> -<p>This will handle routing traffic to our pods.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Service</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp-service</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">LoadBalancer</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">ports</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">protocol</span>: <span style="color:#ae81ff">TCP</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">targetPort</span>: <span style="color:#ae81ff">22</span> -</span></span></code></pre></div><p>Users will be connected in a round-robin fashion to the pods. This manifest will create a service of type LoadBalancer. Which will in turn create a new public Azure Load Balancer in the resource group that contains your Azure Kubernetes Service cluster if one does not already exist. If you already have a public load balancer, a new frontend IP address will be added.</p> -<p>That’s all for now. Please feel free to contact me if you have any questions.</p> - + http://localhost:1313/posts/2022-01-16-azure-kubernetes-sftp-solution/ + In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault. Here is the link to my Github account where you can download the code mentioned in this article: https://github.com/rnemeth90/kubernetes-sftp We will work through the following steps in this article: - diff --git a/public/tags/aks/page/1/index.html b/public/tags/aks/page/1/index.html index 80108266..e644b2e2 100644 --- a/public/tags/aks/page/1/index.html +++ b/public/tags/aks/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/aks/ - + http://localhost:1313/tags/aks/ + - + diff --git a/public/tags/azure-kubernetes-service/index.html b/public/tags/azure-kubernetes-service/index.html index 76388036..cab4dc91 100644 --- a/public/tags/azure-kubernetes-service/index.html +++ b/public/tags/azure-kubernetes-service/index.html @@ -1,849 +1,264 @@ + - - - - - - - + + Tag: Azure Kubernetes Service · GeekyRyan + - + -azure kubernetes service - GeekyRyan - + + + - - - + + + + + + + + + - - - - + + + + + + + - - - - - - - - - + - + + + - - - - - - - - - - + + + + + + + - - - - + - - - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - -
    -
    - -

    Tag: azure kubernetes service

    - - - -
    -
    -
    -

    AKS Scale Down Mode

    -
    - -
    - - -
    - By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete or deallocate nodes. -Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Scheduled Kubernetes Worker Node Maintenance with Kured

    -
    - -
    - - -
    - If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this? -Weaveworks created a great tool for simplifying these steps: Kured (the Kubernetes Reboot Daemon). -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Running Docker in WSL v1

    -
    - -
    - - -
    - I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. -Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Remove Kubernetes Namespace Stuck in the Terminating State

    -
    - -
    - - -
    - In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state. -A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. -
    - - -
    - Read more -
    - - - - - - - -
    - -
    -
    -
    -

    Kubernetes Storage Simplified

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Tag: Azure Kubernetes Service +

    +
    + +
    +
  • + 2022-01-16 + Azure Kubernetes sFTP Solution +
  • -
    -
    -
    -

    Kubernetes Pod Eviction

    -
    - -
    + + - -
    - In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation. -What is Pod Eviction? Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Azure Kubernetes sFTP Solution

    -
    -
    +
    +
    + © -
    - In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault. -Here is the link to my Github account where you can download the code mentioned in this article: -https://github.com/rnemeth90/kubernetes-sftp -We will work through the following steps in this article: -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/azure-kubernetes-service/index.xml b/public/tags/azure-kubernetes-service/index.xml index c99768b4..cc6b9c1c 100644 --- a/public/tags/azure-kubernetes-service/index.xml +++ b/public/tags/azure-kubernetes-service/index.xml @@ -1,643 +1,61 @@ - azure kubernetes service on GeekyRyan - https://rnemeth90.github.io/tags/azure-kubernetes-service/ - GeekyRyan (azure kubernetes service) - Hugo -- gohugo.io - en-us + Azure Kubernetes Service on GeekyRyan + http://localhost:1313/tags/azure-kubernetes-service/ + Recent content in Azure Kubernetes Service on GeekyRyan + Hugo + en Tue, 19 Jul 2022 00:00:00 +0000 - - - - + AKS Scale Down Mode - https://rnemeth90.github.io/posts/2022-07-19-aks-scale-down-mode/ + http://localhost:1313/posts/2022-07-19-aks-scale-down-mode/ Tue, 19 Jul 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-07-19-aks-scale-down-mode/ - <p>By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete <em>or</em> deallocate nodes.</p> -<p>Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. However, you will still need to pay for any storage that the node is using. Having persistent storage also means that any container images that were cached on the node will still be there when the node starts back up. This can be a major performance benefit if you are using Windows containers because the images for these containers are typically very large.</p> -<p>Scale down mode can be configured in several ways. Here, we will look at configuring it via the Azure CLI and Terraform.</p> -<p>Azure CLI:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>az aks nodepool update --scale-down-mode Deallocate --name nplinux01 --cluster-name myAKSCluster --resource-group myResourceGroup -</span></span></code></pre></div><p>Terraform:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-hcl" data-lang="hcl"><span style="display:flex;"><span><span style="color:#66d9ef">resource</span> <span style="color:#e6db74">&#34;azurerm_kubernetes_cluster_node_pool&#34; &#34;nodepool&#34;</span> { -</span></span><span style="display:flex;"><span> name <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;nplinux01&#34;</span> -</span></span><span style="display:flex;"><span> kubernetes_cluster_id <span style="color:#f92672">=</span> <span style="color:#66d9ef">azurerm_kubernetes_cluster</span>.<span style="color:#66d9ef">example</span>.<span style="color:#66d9ef">id</span> -</span></span><span style="display:flex;"><span> vm_size <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Standard_DS2_v2&#34;</span> -</span></span><span style="display:flex;"><span> node_count <span style="color:#f92672">=</span> <span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span> scale_down_mode <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Deallocate&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> tags <span style="color:#f92672">=</span> { -</span></span><span style="display:flex;"><span> Environment <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;lab&#34;</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><em>At the time of this writing, Terraform does not support configuring scale-down mode for the default AKS node pool.</em> -<em>Node pools using ephemeral disks do not support &lsquo;deallocate&rsquo; mode</em></p> - + http://localhost:1313/posts/2022-07-19-aks-scale-down-mode/ + By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete or deallocate nodes. Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. - Scheduled Kubernetes Worker Node Maintenance with Kured - https://rnemeth90.github.io/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ + http://localhost:1313/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ Fri, 15 Jul 2022 18:18:50 +0000 - - https://rnemeth90.github.io/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ - <p>If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this?</p> -<p>Weaveworks created a great tool for simplifying these steps: Kured (the <em><strong>Ku</strong>bernetes <strong>Re</strong>boot <strong>D</strong>aemon</em>). Let’s start by deploying Kured to our cluster.</p> -<p>Kured can be deployed in one of several ways. In this article, we’ll focus on deploying it via Helm. This is the simplest and quickest way to get it running in our cluster.</p> -<p>Follow these steps to install the Helm chart:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># 1) Add the Kured Helm repository</span> -</span></span><span style="display:flex;"><span>helm repo add kured https://weaveworks.github.io/kured -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 2) Update your local Helm chart repository cache</span> -</span></span><span style="display:flex;"><span>helm repo update -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 3) Create a dedicated namespace where you would like to deploy kured</span> -</span></span><span style="display:flex;"><span>kubectl create namespace kured -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 4) Install kured in that namespace with Helm 3 (only on Linux nodes)</span> -</span></span><span style="display:flex;"><span>helm install kured kured/kured --namespace kured --set nodeSelector.<span style="color:#e6db74">&#34;kubernetes\.io/os&#34;</span><span style="color:#f92672">=</span>linux -</span></span></code></pre></div><p>If all went well with the command above, that’s it, you’re done! Have a nice day! 🙂</p> -<p>If you want to test Kured, login to one of your Linux nodes, and install some patches with your package manager of choice (any patch that requires a reboot, typically patches that modify kernel headers). Then, check for a file named ‘reboot-required’ in /var/run:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>ls -lisa /var/run/reboot-required -</span></span></code></pre></div><p>If you installed patches, and this file does not exist, none of your patches require a reboot. We can still fake the system into thinking a reboot is required by manually creating the ‘reboot-required’ file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo touch /var/run/reboot-required -</span></span></code></pre></div><p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-1.png" alt=""></p> -<p>Then, we’ll use Kubetail to tail the logs of all our Kured pods:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubetail -label kured --namespace kured -</span></span></code></pre></div><p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-1024x749.png" alt=""></p> -<p>By default, Kured checks for the existence of the sentinel file every 60 minutes. However, this behavior can be changed. See the github repo for more info:</p> -<p><img src="https://github.com/weaveworks/kured#reboot-sentinel-file--period" alt="weaveworks/kured: Kubernetes Reboot Daemon"></p> -<p>Scheduling on the node should be disabled if you are within the Kured schedule</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-2.png" alt=""></p> -<p>Now that the node is cordoned off, running pods on the node are drained, and the node is rebooted.</p> -<p>That’s it for this article. Have a great day!</p> - + http://localhost:1313/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ + If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this? Weaveworks created a great tool for simplifying these steps: Kured (the Kubernetes Reboot Daemon). - Running Docker in WSL v1 - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ Sun, 26 Jun 2022 15:00:28 +0000 - - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ - <p>I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate.</p> -<p>Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. I receive this nice message:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ docker -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>The command <span style="color:#e6db74">&#39;docker&#39;</span> could not be found in this WSL <span style="color:#ae81ff">1</span> distro. -</span></span><span style="display:flex;"><span>We recommend to convert this distro to WSL <span style="color:#ae81ff">2</span> and activate -</span></span><span style="display:flex;"><span>the WSL integration in Docker Desktop settings. -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>See https://docs.docker.com/docker-for-windows/wsl/ <span style="color:#66d9ef">for</span> details. -</span></span></code></pre></div><p>So I’m in somewhat of a catch-22 here…</p> -<p>To work around this problem until a proper solution is found, I was able to get Docker working with WSL v1.</p> -<p>If you happen to be having a similar issue (and it seems like quite a few people are, considering the number of Github posts I found), just follow these steps:</p> -<ul> -<li>Expose the Docker daemon in docker desktop settings:</li> -</ul> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/02/image-10-1024x585.png"></a></p> -<p>Install the stand-alone Docker client in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ tar zxvf docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ cd docker -</span></span></code></pre></div><p>Set the default Docker daemon in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>export DOCKER_HOST<span style="color:#f92672">=</span>tcp://localhost:2375 -</span></span></code></pre></div><p>Verify you can connect to Docker running on Windows from within WSL:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>./docker info -</span></span></code></pre></div><p>This is also beneficial in that you only have one Docker host to manage your containers, network, etc., rather than two.</p> - + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ + I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. - Remove Kubernetes Namespace Stuck in the Terminating State - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ Sat, 04 Jun 2022 18:29:41 +0000 - - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ - <p>In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state.</p> -<p>A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. One day, you decide you no longer want this blog, so you plan to delete it. Rather than tediously deleting all of the various entities associated with this blog, you can delete the namespace that contains these entities. This will essentially ‘cascade delete’ the resources within the namespace as well.</p> -<p>After deleting the namespace for your blog, you notice that it still exists, but the state of it is ‘Terminating’, and it has been like this for a long time (hours or maybe even days).</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/06/image.png"></a></p> -<p>Kubernetes will occassionally fail to delete third-party resources when deleting a namespace, causing the namespace to linger. This can happen if the third-party API managing the resource is not responding to requests. To verify if any of these resources still exist, use this command:</p> -<pre tabindex="0"><code>kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get --show-kind --show-all --ignore-not-found -n &lt;terminating-namespace&gt; -</code></pre><p>If you happen to see any resources in the output, you can try force deleting them and then try to delete the namespace again.</p> -<p>In my experience, the majority of the time you will not find any resources still hanging around. Rather, the namespace will be completely empty. What is going on here?</p> -<p>Let’s take a look at the namespace:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ae81ff">$ kubectl get namespace darn-c101 -o yaml</span> -</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Namespace</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">annotations</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">kubectl.kubernetes.io/last-applied-configuration</span>: <span style="color:#ae81ff">|</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">kubernetes.io/metadata.name</span>: <span style="color:#ae81ff">darn-c101</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">finalizers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">kubernetes</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">status</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">conditions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">lastTransitionTime</span>: <span style="color:#e6db74">&#34;2022-06-01T19:05:31Z&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">message: &#39;Some content in the namespace has finalizers remaining</span>: <span style="color:#ae81ff">darn-c101.geekyryan.io/finalizer in 1 resource instances&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">reason</span>: <span style="color:#ae81ff">SomeFinalizersRemain</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">status</span>: <span style="color:#e6db74">&#34;True&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">NamespaceFinalizersRemaining</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">phase</span>: <span style="color:#ae81ff">Terminating</span> -</span></span></code></pre></div><p>Notice the inclusion of the finalizers field in the above JSON. Some namespaces have a finalizer defined under spec.</p> -<p>A finalizer is a special metadata key that tells Kubernetes to wait until a specific condition is met before it fully deletes a resource. Much like a finalizer in the .NET framework (does Java have those too? 😀 )</p> -<p>So when you run a command like <code>kubectl delete namespace &lt;namespace&gt;</code>, Kubernetes checks for a finalizer in the <code>metadata.finalizers</code> field. If the resource defined in the finalizer cannot be deleted, then the namespace is not deleted either. This puts the namespace into a perpetual terminating state and is never actually deleted.</p> -<p>When an object has been terminating for an excessive time, check its finalizers by inspecting the <code>metadata.finalizers</code> field in its YAML.</p> -<p>So we now know what the problem is. How can we solve it? Well, it’s actually quite simple. If you are using bash, use this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> -</span></span><span style="display:flex;"><span>namespaces<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>kubectl get ns --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Terminating -o jsonpath<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;{range .items[*]}{.metadata.name}{&#34;\n&#34;}{end}&#39;</span><span style="color:#66d9ef">)</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -z <span style="color:#e6db74">&#34;</span>$namespaces<span style="color:#e6db74">&#34;</span><span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">&#34;No namespaces to delete.&#34;</span> -</span></span><span style="display:flex;"><span> exit -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> namespace in $namespaces -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">do</span> -</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">&#34;[Removing Namespace]: </span>$namespace<span style="color:#e6db74">&#34;</span> -</span></span><span style="display:flex;"><span> kubectl get namespace $namespace -o json | tr -d <span style="color:#e6db74">&#34;\n&#34;</span> | sed <span style="color:#e6db74">&#34;s/\&#34;finalizers\&#34;: \[[^]]\+\]/\&#34;finalizers\&#34;: []/&#34;</span> | kubectl replace --raw /api/v1/namespaces/$namespace/finalize -f - &gt; /dev/null 2&gt;&amp;<span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">done</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span> -</span></span></code></pre></div><p><a href="https://gist.github.com/rnemeth90/e83bb4c8808f0d28412cb40edb2487d3">Delete Terminating Kubernetes Namespaces with Bash (github.com)</a></p> -<p>It will search for any namespace that is stuck in the terminating state and forcefully remove it by removing the finalizers field and then using <code> kubectl replace</code> to commit the change back to the Kube API.</p> -<p>If you prefer Powershell, you can use this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$terminatingNamespaces = kubectl get ns --field-selector=status.phase==Terminating -o jsonpath=<span style="color:#e6db74">&#34;{range .items[*]}{.metadata.name}{&#39;\n&#39;}{end}&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($ns <span style="color:#66d9ef">in</span> $terminatingNamespaces) { -</span></span><span style="display:flex;"><span> Write-Verbose <span style="color:#e6db74">&#39;[FOUND]: Forcefully removing $ns&#39;</span> -</span></span><span style="display:flex;"><span> $jsonObj = kubectl get namespace $ns -o json | ConvertFrom-Json | foreach-object { $_.spec.finalizers = @(); $_ } | -</span></span><span style="display:flex;"><span> convertto-json | kubectl replace --raw /api/v1/namespaces/$namespace/finalize <span style="color:#f92672">-f</span> - -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><a href="https://gist.github.com/rnemeth90/19d7de622a5009c1cf908c5d4deb5358">Delete Terminating Kubernetes Namespaces with Powershell (github.com)</a></p> -<p>It does the same thing as the bash script, just in more of a Window-zy way.</p> -<p>It’s that simple. I hope this was helpful. If you have any questions, comments, or concerns, please feel free to reach out.</p> - + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state. A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. - Kubernetes Storage Simplified - https://rnemeth90.github.io/posts/2022-03-01-kubernetes-storage-simplified/ + http://localhost:1313/posts/2022-03-01-kubernetes-storage-simplified/ Tue, 01 Mar 2022 08:37:58 +0000 - - https://rnemeth90.github.io/posts/2022-03-01-kubernetes-storage-simplified/ - <p>In this blog post, we will attempt to explain the current storage options that exist in Kubernetes. If you are new to Kubernetes, learning about its capabilities of managing the application state can be a daunting task.</p> -<p>Container images are built-in layers, with the runtime layer being writable. However, any files on this writable layer are only available for the container’s lifetime. We can mount a volume to a directory inside the container to have persistent data.</p> -<p>Kubernetes storage uses the concepts of volumes. Ephemeral volumes are called volumes and only last the lifetime of a pod, and “persistent volumes” are used for long-term storage. A typical use case for Ephemeral volumes is storing logs that are not sent to stdout.</p> -<p>Mounting a persistent volume inside a container allows you to persist the state of your application long after the container is terminated. Persistent volumes can also take advantage of the typical storage idiosyncrasies such as backup, compression, and encryption.</p> -<h2 id="persistent-volumes" >Persistent Volumes -<span> - <a href="#persistent-volumes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Kubernetes has several types of persistent volumes. At its core, a persistent volume is simply a directory mounted inside a pod. How that volume is created, the configuration options and the medium that backs it are all determined by the type of volume created.</p> -<p>There are several types of volumes available, too many to list here. You may commonly see some volume types: NFS, iSCSI, hostpath, and local. If your Kubernetes cluster exists in a cloud environment such as Azure or AWS, other volume types are available to you (azureDisk, azureFile, and awsElasticBlockStore, respectively). A complete list of types can be found here:</p> -<p><a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes">https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes</a></p> -<p>Creating a persistent volume is generally a simple task. The first step is determining the type of volume to create. In this post, we will cover creating a local volume. A local volume represents a disk, partition, or directory shared from a node. Local volumes are subject to the availability of the underlying node, meaning that if the node is offline, the volume is also offline and will not be accessible by any pod. Because of this, local volumes should not be used in production.</p> -<p>A persistent volume can only be created using a declarative approach. To create a persistent local volume, use the following YAML definition:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolume</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">example-pv</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">capacity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMode</span>: <span style="color:#ae81ff">Filesystem</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteOnce</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeReclaimPolicy</span>: <span style="color:#ae81ff">Delete</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">local-storage</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">local</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># the path to the volume or directory on the node</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/mnt/disks/ssd1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeAffinity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">required</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeSelectorTerms</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">matchExpressions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">key</span>: <span style="color:#ae81ff">kubernetes.io/hostname</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">operator</span>: <span style="color:#ae81ff">In</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">values</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># name of the node sharing the volume</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">node01</span> -</span></span></code></pre></div><p>When creating a persistent volume of this type, you must specify a node affinity. This ensures that the Kubernetes scheduler schedules any pods requesting access to this volume on the correct node. For example, any pod requesting access to the persistent volume named ‘example-PV will only be scheduled on the node ‘node01’.</p> -<p>Let’s dive into this persistent volume spec a bit more:</p> -<p>You can change the capacity of the persistent volume by updating:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">capacity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span></code></pre></div><p>The accessModes will be determined by the storage provider being used. There are generally 3 access modes available: ReadWriteOnce, ReadWriteMany, and ReadOnlyMany.</p> -<ul> -<li>ReadWriteOnce – The volume can be mounted as read-write by a single node</li> -<li>ReadWriteMany – The volume can be mounted as read-write by many nodes</li> -<li>ReadOnlyMany – The volume can be mounted as read-only by many nodes</li> -</ul> -<p>The “persistentVolumeReclaim” policy determines what happens to a persistent volume when it is no longer mounted by any pods (i.e., there are no claims to it, more on this later). There are three options available for the reclaim policy:</p> -<ul> -<li>Retain – The persistent volume is kept as-is. It must be manually removed when no longer needed.</li> -<li>Recycle – The persistent volume is scrubbed and can be re-used by other pods</li> -<li>Delete – The persistent volume is deleted.</li> -</ul> -<p>Currently, only NFS and hostPath volumes support recycling. Cloud storage providers (Azure, AWS, and GCE) support deletion.</p> -<p>The other aspects of this spec are unique to the volume being used. Since we are using a local volume here, we must specify the path to the directory or volume on the host and the host which is sharing the directory or volume:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span> <span style="color:#f92672">local</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># the path to the volume or directory on the node</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/mnt/disks/ssd1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeAffinity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">required</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeSelectorTerms</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">matchExpressions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">key</span>: <span style="color:#ae81ff">kubernetes.io/hostname</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">operator</span>: <span style="color:#ae81ff">In</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">values</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># name of the node sharing the volume</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">node01</span> -</span></span></code></pre></div><h2 id="ephemeral-volumes" >Ephemeral Volumes -<span> - <a href="#ephemeral-volumes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Note: The Kubernetes documentation recognizes configMaps and Secrets as ephemeral volumes. However, in this article, we will only discuss ephemeral volumes used for data storage (emptyDir volumes).</p> -<p>Ephemeral volumes are defined within the context of a pod. This means that you cannot create an ephemeral volume on its own. Instead, define the ephemeral volume in the pod or a deployment spec.</p> -<p>Ephemeral volumes are useful in a few scenarios:</p> -<ol> -<li>You want to share data between multiple containers in a pod</li> -<li>You want to cache temporary information such as log files</li> -<li>You need scratch space to store data before it is processed by another container or pod</li> -</ol> -<p>If one of the containers in the pod happens to restart, data on the ephemeral volume will still exist; as long as one of the containers is mounting, it stays online. In other words, if a pod mounting the ephemeral volume is removed from a node, data on the ephemeral volume is lost. However, if a pod crashes, the data on the volume remains intact.</p> -<p>As stated previously, creating an ephemeral volume is done as part of the pod or deployment template:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/cache</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">emptyDir</span>: {} -</span></span></code></pre></div><p>If the template, you add a volume of type ’emptyDir’ in the ‘volumes’ spec and name it. You can mount this volume in any container in the pod. The volume does not have to be mounted to the same directory in each container.</p> -<h2 id="persistent-volume-claims" >Persistent Volume Claims -<span> - <a href="#persistent-volume-claims"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>A persistentVolumeClaim (often referred to as a ‘PVC’) is used by a pod to create a ‘claim’ on storage. Using a PVC, a pod can mount multiple persistent volumes simultaneously to any directory in the pod.</p> -<p>PersistentVolumeClaim’s are a Kubernetes primitive that can be deployed from a manifest:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fast-storage-pvc</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMode</span>: <span style="color:#ae81ff">Filesystem</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">8Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">fast</span> -</span></span></code></pre></div><p>Most of the options in the manifest above seem pretty obvious. The volumeMode specifies whether to consume the persistent volume as a FileSystem or block device. The resources section helps specify the amount of storage you require (8Gi in this example). We will cover the storageClassName in the next section. Finally, the accessModes are identical to those described above in the Persistent Volumes section.</p> -<p>Pods access a volume by using the persistentVolumeClaim as volume. Claims must exist in the same namespace as the pod using the claim. The controller finds the claim in the pods’ namespace and uses it to find a persistent volume capable of backing the claim. The volume is then mounted on the host and attached to the pod.</p> -<p>To create a pod that utilizes a PVC, use the following yaml definition:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/mnt/share</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span></code></pre></div><h2 id="storage-classes" >Storage Classes -<span> - <a href="#storage-classes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>In this article, we will only be referencing Kubernetes storage classes with respect to dynamic provisioners. If you would like to learn more, please reference the Kubernetes docs:</p> -<p><a href="https://bit.ly/3ruJD2A">https://bit.ly/3ruJD2A</a></p> -<p>Storage Classes have many uses. Kubernetes is unopinionated about what a storage class represents. They can be used to represent different characteristics of storage (performance, compression method, file system modes, etc.). Storage Classes can also be used to provision persistent volumes dynamically, which will be the focus of this article.</p> -<p>Storage classes are often packaged with CSI drivers. Each StorageClass contains the fields “provisioner”, “parameters”, and “reclaimPolicy”. The provisioner field is used to determine what CSI driver is used for provisioning volumes.</p> -<p>This is an example of the storage class packaged with the AzureFiles CSI driver:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">StorageClass</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">storage.k8s.io/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azurefileshare</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">provisioner</span>: <span style="color:#ae81ff">file.csi.azure.com</span> <span style="color:#75715e"># replace with &#34;kubernetes.io/azure-file&#34; if aks version is less than 1.21</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">mountOptions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">dir_mode=0777</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">file_mode=0777</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">uid=0</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">gid=0</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">mfsymlinks</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">cache=strict</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">actimeo=30</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">parameters</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">skuName</span>: <span style="color:#ae81ff">Standard_LRS</span> -</span></span></code></pre></div><p>You can see in the above manifest that the provisioner is set to ‘file.csi.azure.com.’ When a pod uses a PVC in its manifest that references this storage class, the provisioner will dynamically manage the underlying storage.</p> -<p>The name of the storageClass is referenced in the persistentVolumeClaim:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">8Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">azurefileshare</span> -</span></span></code></pre></div><p>You could then reference this PVC in a pod:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/mnt/share</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span></code></pre></div><p>That concludes this article. I know that is a lot of information! As always, if you have any questions or comments, please reach out.</p> - + http://localhost:1313/posts/2022-03-01-kubernetes-storage-simplified/ + In this blog post, we will attempt to explain the current storage options that exist in Kubernetes. If you are new to Kubernetes, learning about its capabilities of managing the application state can be a daunting task. Container images are built-in layers, with the runtime layer being writable. However, any files on this writable layer are only available for the container’s lifetime. We can mount a volume to a directory inside the container to have persistent data. - Kubernetes Pod Eviction - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ Sat, 05 Feb 2022 23:49:16 +0000 - - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ - <p>In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation.</p> -<h2 id="what-is-pod-eviction" >What is Pod Eviction? -<span> - <a href="#what-is-pod-eviction"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. The most common of which is resource starvation on a node. This is referred to as “node-pressure eviction.”</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>NAME READY STATUS RESTARTS AGE -</span></span><span style="display:flex;"><span>nginx 0/1 Evicted <span style="color:#ae81ff">0</span> 10s -</span></span></code></pre></div><h2 id="eviction-process" >Eviction Process -<span> - <a href="#eviction-process"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The kubelet process running on the node monitors resources such as CPU, memory, disk space, inodes, etc. When one of these resources reaches a certain consumption level, the kubelet will first attempt to clean up resources by deleting non-running pods and images (in the case of storage starvation). The kubelet will then fail one or more pods on the node to reclaim resources. The class of the pod determines the order in which it does this.</p> -<p><strong>Pod Classes</strong></p> -<ul> -<li>Guaranteed: Pods that have requests and limits configured for both CPU and memory</li> -<li>Burstable: Pods with a resource request configured for memory or CPU</li> -<li>Best Effort: Pods without any requests or limits</li> -</ul> -<p>The kubelet will first evict any “best-effort” pods. If this is not enough, the kubelet will evict any “burstable” pods. Pods within the “guaranteed” class are theoretically safe from eviction.</p> -<p>During a node-pressure eviction, the kubelet sets the PodPhase for the selected pods to “Failed.” This causes the pods to terminate. If a daemonSet or replicaSet manages the pod, the Kubernetes controller-manager will create new pods on another node.</p> -<h2 id="recovery" >Recovery -<span> - <a href="#recovery"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Node-pressure eviction is almost always avoidable. We can prevent this type of issue by ensuring that we properly size our clusters and create resource limits for pods.</p> -<p><strong>Resource</strong> <strong>Requests and Limits:</strong></p> -<ul> -<li>Requests: The minimum amount of resources (CPU/memory) that a container needs to start.</li> -<li>Limits: The maximum amount of resources that a container is allowed to use.</li> -</ul> -<p>Pod resources and requests can be defined in a pod spec or deployment spec. Below is an example of a pod spec with resource requests and limits defined:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">frontend</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">nginx</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;64Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;250m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">limits</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;128Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;500m&#34;</span> -</span></span></code></pre></div><p>You will often need to clean up evicted pods manually. If you find that your cluster has a large amount of evicted pods, you can clean them up with the following kubectl commands:</p> -<p><strong>To see all failed pods in the cluster:</strong></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl get pod --all-namespaces --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Failed -</span></span></code></pre></div><p><strong>To remove all failed pods in the cluster:</strong></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl delete pod --all-namespaces --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Failed -</span></span></code></pre></div><p>I hope this article has been helpful. Please reach out if you have any questions or comments! Also, if you would like to learn more, take a look at the official Kubernetes docs:</p> -<p><a href="https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/">https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/</a></p> - + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ + In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation. What is Pod Eviction? Link to heading Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. - Azure Kubernetes sFTP Solution - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ + http://localhost:1313/posts/2022-01-16-azure-kubernetes-sftp-solution/ Sun, 16 Jan 2022 07:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ - <p>In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault.</p> -<p>Here is the link to my Github account where you can download the code mentioned in this article:</p> -<p><a href="https://github.com/rnemeth90/kubernetes-sftp">https://github.com/rnemeth90/kubernetes-sftp</a></p> -<p>We will work through the following steps in this article:</p> -<ol> -<li>Deploy the AzureFile CSI driver to the AKS cluster</li> -<li>Create a configMap that our initContainer will</li> -<li>Deploy a persistent volume claim that an Azure File share will back</li> -<li>Deploy a replicaSet consisting of our initContainer and application container</li> -<li>Deploy a service to serve traffic</li> -</ol> -<p>First, you will need to deploy the Azure Files CSI driver to your AKS cluster. AKS uses this daemon set to dynamically provision/destroy Azure NFSv4 File Shares. The Azure Files CSI driver creates a storage account in the node pool resource group, in which it will then provision the file share.</p> -<p>Deploying the Azure Files CSI driver is a simple task. You will need to run this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/install-driver.sh | bash -s master -- -</span></span></code></pre></div><p>You can use the following commands to verify that the daemon set has exists:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl -n kube-system get pod -o wide --watch -l app<span style="color:#f92672">=</span>csi-azurefile-controller -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>kubectl -n kube-system get pod -o wide --watch -l app<span style="color:#f92672">=</span>csi-azurefile-node -</span></span></code></pre></div><figure class="wp-block-coblocks-gallery-masonry masonry-grid has-border-radius-10 has-medium-gutter"><figure class="wp-block-image size-large masonry-brick">[![Image gallery image](https://rnemeth90.github.io/wp-content/uploads/2022/01/image-1-1024x434.png)](https://rnemeth90.github.io/wp-content/uploads/2022/01/image-1.png)</figure></figure>Next, you need to create a storage class by deploying this yaml file: -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl create -f https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/example/storageclass-azurefile-nfs.yaml -</span></span></code></pre></div><p>Read more about the AzureFiles CSI driver at the following Github link:</p> -<p><a href="https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/install-driver-on-aks.md">https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/install-driver-on-aks.md</a></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ConfigMap</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">creationTimestamp</span>: <span style="color:#66d9ef">null</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">testcm</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">init.sh</span>: |-<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> #!/bin/bash -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> CONF_FILE=&#34;/etc/sftp/users.conf&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> KEYVAULT=&#34;Insert name of Key Vault&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_ID=&#34;Insert service principal Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_PASSWORD=&#34;Insert service principal password&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_TENANT_ID=&#34;Insert Az AAD Tenant Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SUBSCRIPTION_ID=&#34;Insert Az Subscription Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az login --service-principal --username &#34;${AZ_SPN_ID}&#34; --password &#34;${AZ_SPN_PASSWORD}&#34; --tenant &#34;${AZ_SPN_TENANT_ID}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az account set --subscription &#34;${AZ_SUBSCRIPTION_ID}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETS+=($(az keyvault secret list --vault-name $KEYVAULT --query &#34;[].id&#34; -o tsv)) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> chmod 755 /home -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [[ -e $CONF_FILE ]]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> rm -rf &#34;${CONF_FILE}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> touch $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> else -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> touch $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> for SECRET in &#34;${SECRETS[@]}&#34;; do -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETNAME=$(basename $SECRET | tr -d &#39;\r&#39;) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETVALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $SECRETNAME --query &#39;value&#39; | tr -d &#39;&#34;&#39; | tr -d &#39;\r&#39;) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;$SECRETNAME:$SECRETVALUE:::upload&#34; &gt;&gt; $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> done -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [[ ! -s $CONF_FILE ]]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;** ERROR: user.conf is empty&#34; 1&gt;&amp;2 -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> exit 1 -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi</span> -</span></span></code></pre></div><p>The initContainer will use this configMap to read secrets from an Azure Key Vault and then write the secrets to the users.conf file. The users.conf file contains user account information. In the Key Vault, the secret name should be the username and the secret value should be the password. This Key Vault must exist and contain the secrets prior to deploying this solution.</p> -<p>When I deployed this solution in my environment, I used an Azure DevOps pipeline to create/manage the Key Vault with Terraform and then deploy the secrets using an inline Powershell script. However, this is beyond the scope of this article, and I will not be covering it here. You will also need to create a Service Principal in your AAD tenant and grant it access to the Key Vault. The Service Principal needs to have at least read access to the Key Vault.</p> -<p>Before deploying the configMap, you need to fill in values for these variables:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span> KEYVAULT<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert name of Key Vault&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert service principal Id&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_PASSWORD<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert service principal password&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_TENANT_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert Az AAD Tenant Id&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SUBSCRIPTION_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert Az Subscription Id&#34;</span> -</span></span></code></pre></div><p>These values pertain to the service principal with read access to the Key Vault. After filling out these variables, you can deploy the configMap using kubectl.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl create -f configmap.yaml -</span></span></code></pre></div><p>You can deploy the PVC using this yaml file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">azurefile-csi-nfs</span> -</span></span></code></pre></div><p>When creating the persistent volume claim for the deployment, you specify azurefile-csi-nfs as the StorageClass. This will create an NFSv4 share in a premium storage account. The reclaim policy of the storage class ensures that the file share is deleted when the associated Persistent Volume is deleted. Change the reclaim policy to “Retain” if you want the file shares to persist after deleting the PV. Furthermore, the storage class enables the file share to be expandable by modifying the storage request size on the PVC.</p> -<p>After deploying the PVC, you can verify its existence by running:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl get pvc -</span></span></code></pre></div><p>You should see output similar to the following (the manifest for the replicaSet is by far the most complicated of all the code referenced here):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Deployment</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">matchLabels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">strategy</span>: {} -</span></span><span style="display:flex;"><span> <span style="color:#f92672">template</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initContainer</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">chmodder</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">mcr.microsoft.com/azure-cli</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">command</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">/bin/sh</span> -</span></span><span style="display:flex;"><span> - -<span style="color:#ae81ff">c</span> -</span></span><span style="display:flex;"><span> - <span style="color:#e6db74">&#34;/scripts/init.sh&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/scripts</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">docker.io/atmoz/sftp:alpine</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">imagePullPolicy</span>: <span style="color:#ae81ff">IfNotPresent</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;64Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;250m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">limits</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;128Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;500m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">livenessProbe</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tcpSocket</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initialDelaySeconds</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">timeoutSeconds</span>: <span style="color:#ae81ff">5</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">periodSeconds</span>: <span style="color:#ae81ff">10</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">failureThreshold</span>: <span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readinessProbe</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tcpSocket</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initialDelaySeconds</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">timeoutSeconds</span>: <span style="color:#ae81ff">5</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">periodSeconds</span>: <span style="color:#ae81ff">10</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">failureThreshold</span>: <span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/home</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/etc/sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">dnsPolicy</span>: <span style="color:#ae81ff">ClusterFirst</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">restartPolicy</span>: <span style="color:#ae81ff">Never</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">configMap</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">emptyDir</span>: {} -</span></span></code></pre></div><p>You may need to change the CPU/memory requests and limits. These values worked for me, but your results may vary. You can also add/change the labels as you see fit.</p> -<p>This will handle routing traffic to our pods.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Service</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp-service</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">LoadBalancer</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">ports</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">protocol</span>: <span style="color:#ae81ff">TCP</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">targetPort</span>: <span style="color:#ae81ff">22</span> -</span></span></code></pre></div><p>Users will be connected in a round-robin fashion to the pods. This manifest will create a service of type LoadBalancer. Which will in turn create a new public Azure Load Balancer in the resource group that contains your Azure Kubernetes Service cluster if one does not already exist. If you already have a public load balancer, a new frontend IP address will be added.</p> -<p>That’s all for now. Please feel free to contact me if you have any questions.</p> - + http://localhost:1313/posts/2022-01-16-azure-kubernetes-sftp-solution/ + In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault. Here is the link to my Github account where you can download the code mentioned in this article: https://github.com/rnemeth90/kubernetes-sftp We will work through the following steps in this article: - diff --git a/public/tags/azure-kubernetes-service/page/1/index.html b/public/tags/azure-kubernetes-service/page/1/index.html index f1b1c278..55aae903 100644 --- a/public/tags/azure-kubernetes-service/page/1/index.html +++ b/public/tags/azure-kubernetes-service/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/azure-kubernetes-service/ - + http://localhost:1313/tags/azure-kubernetes-service/ + - + diff --git a/public/tags/azure/index.html b/public/tags/azure/index.html index 25a8d2cb..3672f79d 100644 --- a/public/tags/azure/index.html +++ b/public/tags/azure/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Azure · GeekyRyan + - - -azure - GeekyRyan - - - - - - - - - - - + - - + + + - + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,887 +79,232 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - -
    -
    - -

    Tag: azure

    - - - -
    -
    -
    -

    Chaining YAML Pipelines in Azure Devops

    -
    - -
    - - -
    - In this article, we’ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to figure this out. -Our two pipelines will exist in the same repository. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Update Azure Devops SPN Secret

    -
    - -
    - - -
    - If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal. -In this article, I’ll show you two methods for updating a secret for a service principal prior to expiration. -Update the secret via the Azure Devops Portal: Go to “Service Connections” in the Azure Devops portal Find the SPN you want to update, then click “Manage Service Principal” Then on the service principal page, click Certificates & Secrets Create a “New Client Secret”, take note of the value Delete the ‘old’ secret Return to the Service Connection in the Azure Devops portal Click Edit - click the verify button. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Accessing Secrets Securely in Azure DevOps Pipelines

    -
    - -
    - - -
    - This post will cover a secure method for accessing secrets in Azure DevOps pipelines. -Why Azure Key Vault? Azure Key Vault is an Azure cloud service used to securely store secrets, keys, and certificates. A secret can be any string of characters, such as API keys, passwords, URLs, etc. Azure Key Vault encrypts data at rest and in transit using HTTPS. Depending on the type of Key Vault you are using, data at rest is encrypted using software encryption (AES 256) or HSM-backed keys. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Azure Kubernetes sFTP Solution

    -
    - -
    - - -
    - In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault. -Here is the link to my Github account where you can download the code mentioned in this article: -https://github.com/rnemeth90/kubernetes-sftp -We will work through the following steps in this article: -
    - - -
    - Read more -
    - - - - - - - -
    - -
    -
    -
    -

    Continuous Deployment Models

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Tag: Azure +

    +
    + +
      -
      - When deploying new software releases to servers or (insert -as-a-service> here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments. -Blue/Green Deployments Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. Instead, it gets deployed to another set of servers (blue) first. -
      - - -
      - Read more -
      - - - - - - - - - -
    +
  • + 2022-11-03 + Chaining YAML Pipelines in Azure Devops +
  • -
    -
    -
    -

    Deploy Azure VMs Using Azure Devops CI/CD Pipeline

    -
    - -
    - +
  • + 2022-09-12 + Update Azure Devops SPN Secret +
  • -
    - This article assumes that you have already created a pipeline in Azure Devops and have it linked to an Azure Devops repo. You will need to create a variable named $vmpassword and assign it the value stored in your key vault. -To create a release pipeline that will automatically create a VM (using the password stored in key vault for the local administrator account), do the following: -Create a new release pipeline 3. -
    +
  • + 2022-02-19 + Accessing Secrets Securely in Azure DevOps Pipelines +
  • +
  • + 2022-01-16 + Azure Kubernetes sFTP Solution +
  • -
    - Read more -
    +
  • + 2022-01-14 + Continuous Deployment Models +
  • +
  • + 2022-01-14 + Deploy Azure VMs Using Azure Devops CI/CD Pipeline +
  • +
  • + 2022-01-14 + Azure Devops &#8211; Self Hosted Agent Service Won&#8217;t Start &#8211; Incorrect Function +
  • - +
  • + 2020-12-16 + Exam AZ-303: Microsoft Azure Architect Technologies Study Guide +
  • - - - - -
    - -
    -
    -
    -

    Azure Devops &#8211; Self Hosted Agent Service Won&#8217;t Start &#8211; Incorrect Function

    -
    - -
    - -
    - I setup a self hosted agent for Azure Devops this morning on Server 2012 R2 (legacy Visual Studio dependencies…) and found that I was unable to start the service. The error I received was “Error 1 Incorrect Function” when attempting to start the service in services.msc. -I was attempting to run the agent from within my user profile downloads folder. I originally was not aware the service would be running from this directory. -
    - - -
    - Read more -
    - - - - - - -
    + -
    -
    -
    -

    Exam AZ-303: Microsoft Azure Architect Technologies Study Guide

    -
    - -
    - -
    - I recently passed the AZ-303 exam. Below are some of the resources I used to prepare for the exam. In addition to the links below, I also used Alan Rodrigues’ course on Udemy. https://www.udemy.com/course/az-102-azure-administrator-certification-transition/ The Udemy course and Microsoft Docs are enough to pass the exam. The course has some good practice exams and labs that align well with what you’ll see on the real exam regarding difficulty. I was scoring in the high 90’s on the Udemy exams. -
    + +
  • 1
  • + + -
    - Read more -
    + - + +
  • 2
  • + - - - -
    - -
    -
    -
    -

    Azure AD Sync &#8211; Set-MsolDirSyncEnabled : You cannot turn off Active Directory synchronization.

    -
    -
    +
    +
    + © -
    - I recently ran into a situation in my lab environment that required I resync all (2000+) user accounts to Azure AD. Though this sounds complex and daunting, its actually quite simple. T -The basic steps involve disabling sync, and then removing the user objects. This can all be done with two PowerShell commands: -1) Set-MsolDirSyncEnabled -EnableDirSync $false -2) Get-MsolUser -All | Remove-MsolUser -force -The account that you are currently running the commands as will not be removed. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    -
    - - - - - - -
    -
    + - - -
    -
    -
    -

    Azure VM Scale Set &#8211; Get Instance IP Address

    -
    - -
    + + + + - -
    - If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal. -There are a few options we have for retrieving information about a VMSS and its instances without using the Azure Portal. -
    - - -
    - Read more -
    - - - + - + - - -
    - - - - - + + + + - - -
    - - + - + -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/azure/index.xml b/public/tags/azure/index.xml index d63f2379..1ac808f2 100644 --- a/public/tags/azure/index.xml +++ b/public/tags/azure/index.xml @@ -1,1384 +1,131 @@ - azure on GeekyRyan - https://rnemeth90.github.io/tags/azure/ - GeekyRyan (azure) - Hugo -- gohugo.io - en-us + Azure on GeekyRyan + http://localhost:1313/tags/azure/ + Recent content in Azure on GeekyRyan + Hugo + en Thu, 03 Nov 2022 00:00:00 +0000 - - - - + Chaining YAML Pipelines in Azure Devops - https://rnemeth90.github.io/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ + http://localhost:1313/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ Thu, 03 Nov 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ - <p>In this article, we&rsquo;ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. -Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to -figure this out.</p> -<p>Our two pipelines will exist in the same repository. We have a dependent-pipeline, that we only want to run once the source-pipeline is finished. This is useful if you have -some infrastructure you want to build, prior to deploying something to that infrastructure.</p> -<p>The process is actually quite simple. First, let&rsquo;s define our source pipeline:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># source-pipeline</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: <span style="color:#ae81ff">echo Hello, world!</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a one-line script&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo Add other tasks to build, test, and deploy your project. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo See https://aka.ms/yaml</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a multi-line script&#39;</span> -</span></span></code></pre></div><p>Nothing fancy here, just the build in template pipeline that Microsoft gives us for free when we create a &ldquo;Starter Pipeline&rdquo;.</p> -<p>Now, let&rsquo;s create another pipeline in the same repo that will be triggered when the pipeline above completes:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># dependent-pipeline</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">none</span> <span style="color:#75715e"># we want this pipeline to be triggered manually, not based on PR, etc.</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">pipelines</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">pipeline</span>: <span style="color:#ae81ff">source-pipeline</span> <span style="color:#75715e">#this can be anything</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">source</span>: <span style="color:#e6db74">&#39;source-pipeline&#39;</span> <span style="color:#75715e">#this needs to be the name of the &#39;source&#39; pipeline</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">trigger</span>: <span style="color:#66d9ef">true</span> <span style="color:#75715e"># Run dependent-pipeline pipeline when any run of security-lib-ci completes</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: <span style="color:#ae81ff">echo Hello, world!</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a one-line script&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo Add other tasks to build, test, and deploy your project. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo See https://aka.ms/yaml</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a multi-line script&#39;</span> -</span></span></code></pre></div><p>The resources block above defines our dependency. You want to be sure to configure the trigger of the dependent pipeline appropriately as well.</p> -<p>There are several options for fine-tuning this process. See the office Microsoft documentation below:</p> -<p><a href="https://learn.microsoft.com/en-us/azure/devops/pipelines/process/pipeline-triggers?view=azure-devops">Link to the Microsoft Docs</a></p> - + http://localhost:1313/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ + In this article, we&rsquo;ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to figure this out. Our two pipelines will exist in the same repository. - Update Azure Devops SPN Secret - https://rnemeth90.github.io/posts/2022-09-12-update-azure-devops-spn-secret/ + http://localhost:1313/posts/2022-09-12-update-azure-devops-spn-secret/ Mon, 12 Sep 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-09-12-update-azure-devops-spn-secret/ - <p>If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal.</p> -<p>In this article, I&rsquo;ll show you two methods for updating a secret for a service principal prior to expiration.</p> -<h1 id="update-the-secret-via-the-azure-devops-portal" >Update the secret via the Azure Devops Portal: -<span> - <a href="#update-the-secret-via-the-azure-devops-portal"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h1><ul> -<li>Go to &ldquo;Service Connections&rdquo; in the Azure Devops portal</li> -<li>Find the SPN you want to update, then click &ldquo;Manage Service Principal&rdquo;</li> -<li>Then on the service principal page, click Certificates &amp; Secrets</li> -<li>Create a &ldquo;New Client Secret&rdquo;, take note of the value</li> -<li>Delete the &lsquo;old&rsquo; secret</li> -<li>Return to the Service Connection in the Azure Devops portal</li> -<li>Click Edit - click the verify button. It should tell you the client certificate has expired</li> -<li>Now you need to make an arbitrary change and save it. I just type a character in the optional description and save.</li> -<li>Now edit again and click verify, it will now pick up the new client secret and all is happy.</li> -<li>You can now remove whatever you added to the description.</li> -</ul> - + http://localhost:1313/posts/2022-09-12-update-azure-devops-spn-secret/ + If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal. In this article, I&rsquo;ll show you two methods for updating a secret for a service principal prior to expiration. Update the secret via the Azure Devops Portal: Link to heading Go to &ldquo;Service Connections&rdquo; in the Azure Devops portal Find the SPN you want to update, then click &ldquo;Manage Service Principal&rdquo; Then on the service principal page, click Certificates &amp; Secrets Create a &ldquo;New Client Secret&rdquo;, take note of the value Delete the &lsquo;old&rsquo; secret Return to the Service Connection in the Azure Devops portal Click Edit - click the verify button. - Accessing Secrets Securely in Azure DevOps Pipelines - https://rnemeth90.github.io/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ + http://localhost:1313/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ Sat, 19 Feb 2022 16:02:50 +0000 - - https://rnemeth90.github.io/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ - <p>This post will cover a secure method for accessing secrets in Azure DevOps pipelines.</p> -<h2 id="why-azure-key-vault" >Why Azure Key Vault? -<span> - <a href="#why-azure-key-vault"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Azure Key Vault is an Azure cloud service used to securely store secrets, keys, and certificates. A secret can be any string of characters, such as API keys, passwords, URLs, etc. Azure Key Vault encrypts data at rest and in transit using HTTPS. Depending on the type of Key Vault you are using, data at rest is encrypted using software encryption (AES 256) or HSM-backed keys.</p> -<p>Azure Key Vault also gives us the ability to control access to secrets, keys, and certificates using native Key Vault access policies or the newer option of Azure IAM (RBAC) integration.</p> -<h2 id="what-are-variable-groups" >What are Variable Groups? -<span> - <a href="#what-are-variable-groups"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>It’s all in the name. Variable groups are simply a method of grouping Azure DevOps pipeline variables. If you created a release for an application named MyAwesomeApp, you could create a variable group named myawesomeapp-var-group that could then store all of the variables you reference in the release. It’s simply a method of organizing variables.</p> -<p>You apply permissions to variable groups so that only certain people and pipelines/releases are able to use them.</p> -<p>You can read more here about variable groups and their usage:</p> -<p><a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/library/variable-groups?view=azure-devops&amp;tabs=yaml#use-a-variable-group">https://docs.microsoft.com/en-us/azure/devops/pipelines/library/variable-groups?view=azure-devops&amp;tabs=yaml#use-a-variable-group</a></p> -<h2 id="creating-a-key-vault-and-adding-secrets" >Creating a Key Vault and Adding Secrets -<span> - <a href="#creating-a-key-vault-and-adding-secrets"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p><strong>If you already have a Key Vault, skip this section.</strong></p> -<p>In this post, we will create a Key Vault using the AzureCLI. To create the Vault and a secret, run these commands:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># Create a resource group</span> -</span></span><span style="display:flex;"><span>az group create --location &lt;location&gt; --name &lt;resource-group-name&gt; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Create a KeyVault</span> -</span></span><span style="display:flex;"><span>az keyvault create --name &lt;keyvault-name&gt; --resource-group &lt;resource-group-name&gt; --enable-soft-delete -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Create some secrets in the Key Vault</span> -</span></span><span style="display:flex;"><span>az keyvault secret set --name username --vault-name &lt;keyvault-name&gt; --value &lt;username&gt; -</span></span><span style="display:flex;"><span>az keyvault secret set --name password --vault-name &lt;keyvault-name&gt; --value &lt;password&gt; -</span></span><span style="display:flex;"><span>az keyvault secret set --name tenantId--vault-name &lt;keyvault-name&gt; --value &lt;tenant id&gt; -</span></span></code></pre></div><p>You will need to update the location and resource group name with whatever values you want. You will also need to update the username, password, and your Azure AD tenant ID. The username you choose will need read access to your subscription.</p> -<h2 id="creating-a-variable-group" >Creating a Variable Group -<span> - <a href="#creating-a-variable-group"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Now we’ll create the variable group in Azure DevOps.</p> -<p>Go to your Azure DevOps project &gt; Pipelines &gt; Library and click “+ Variable Group”:</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image.png"></a></p> -<p>Give your variable group a name. Then toggle the switch “Link secrets from an Azure key vault as variables”. Select your Azure Subscription (you may need to authorize DevOps access to the subscription, and then select the Key Vault.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-1.png"></a></p> -<p>Now we can add the secrets from the Key Vault to the variable group. Under “Variables”, click the “+ Add” button. Select the checkbox next to any secrets you want to add to the variable group, and then click “Ok”.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-7.png"></a></p> -<p>Finally, click the “Save” button. You now have a variable group with secrets linked to a Key Vault. Notice the name of the secret is the only thing visible from the variable group. If you were to update the secret value in the Key Vault, Azure DevOps would automatically pick up the new value.</p> -<h2 id="use-the-variable-group-in-a-pipeline" >Use the Variable Group in a Pipeline -<span> - <a href="#use-the-variable-group-in-a-pipeline"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Now that we have our variable group in place, let’s use it in a pipeline. In Azure DevOps, go to Pipelines and click “New pipeline”.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-8-1024x596.png"></a></p> -<p>Choose “Azure Repos Git” &gt; “&lt; your git repo&gt; “, “Starter Pipeline”, and then paste in the following code (You will need to update the ‘azureSubscription’ field with your SPN):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">variables</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">group</span>: <span style="color:#ae81ff">kv-secrets</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pr</span>: <span style="color:#ae81ff">none</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">stages</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">stage</span>: <span style="color:#ae81ff">print_resource_groups</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">jobs</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">job</span>: <span style="color:#ae81ff">print_resource_groups</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">continueOnError</span>: <span style="color:#66d9ef">false</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">task</span>: <span style="color:#ae81ff">AzureCLI@2</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">inputs</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">azureSubscription</span>: <span style="color:#e6db74">&#39;&lt;Your SPN&gt;&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">scriptType</span>: <span style="color:#e6db74">&#39;bash&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">scriptLocation</span>: <span style="color:#e6db74">&#39;inlineScript&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">inlineScript</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az login --service-principal --username $(username) --password $(password) --tenant $(tenantId) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az group list</span> -</span></span></code></pre></div><p>Now click “Save and Run”, and then “Save and Run” again.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-9-1024x596.png"></a></p> -<p>Once the pipeline finishes running, you can see that it was able to read the subscription and create a list of all resource groups found.</p> -<p>This is a simple example of using Key Vault credentials in a pipeline. But you can imagine how useful this could be in more complex scenarios.</p> -<p>That’s all for now. If you have any questions, feel free to reach out!</p> - + http://localhost:1313/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ + This post will cover a secure method for accessing secrets in Azure DevOps pipelines. Why Azure Key Vault? Link to heading Azure Key Vault is an Azure cloud service used to securely store secrets, keys, and certificates. A secret can be any string of characters, such as API keys, passwords, URLs, etc. Azure Key Vault encrypts data at rest and in transit using HTTPS. Depending on the type of Key Vault you are using, data at rest is encrypted using software encryption (AES 256) or HSM-backed keys. - Azure Kubernetes sFTP Solution - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ + http://localhost:1313/posts/2022-01-16-azure-kubernetes-sftp-solution/ Sun, 16 Jan 2022 07:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ - <p>In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault.</p> -<p>Here is the link to my Github account where you can download the code mentioned in this article:</p> -<p><a href="https://github.com/rnemeth90/kubernetes-sftp">https://github.com/rnemeth90/kubernetes-sftp</a></p> -<p>We will work through the following steps in this article:</p> -<ol> -<li>Deploy the AzureFile CSI driver to the AKS cluster</li> -<li>Create a configMap that our initContainer will</li> -<li>Deploy a persistent volume claim that an Azure File share will back</li> -<li>Deploy a replicaSet consisting of our initContainer and application container</li> -<li>Deploy a service to serve traffic</li> -</ol> -<p>First, you will need to deploy the Azure Files CSI driver to your AKS cluster. AKS uses this daemon set to dynamically provision/destroy Azure NFSv4 File Shares. The Azure Files CSI driver creates a storage account in the node pool resource group, in which it will then provision the file share.</p> -<p>Deploying the Azure Files CSI driver is a simple task. You will need to run this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/install-driver.sh | bash -s master -- -</span></span></code></pre></div><p>You can use the following commands to verify that the daemon set has exists:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl -n kube-system get pod -o wide --watch -l app<span style="color:#f92672">=</span>csi-azurefile-controller -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>kubectl -n kube-system get pod -o wide --watch -l app<span style="color:#f92672">=</span>csi-azurefile-node -</span></span></code></pre></div><figure class="wp-block-coblocks-gallery-masonry masonry-grid has-border-radius-10 has-medium-gutter"><figure class="wp-block-image size-large masonry-brick">[![Image gallery image](https://rnemeth90.github.io/wp-content/uploads/2022/01/image-1-1024x434.png)](https://rnemeth90.github.io/wp-content/uploads/2022/01/image-1.png)</figure></figure>Next, you need to create a storage class by deploying this yaml file: -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl create -f https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/example/storageclass-azurefile-nfs.yaml -</span></span></code></pre></div><p>Read more about the AzureFiles CSI driver at the following Github link:</p> -<p><a href="https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/install-driver-on-aks.md">https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/install-driver-on-aks.md</a></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ConfigMap</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">creationTimestamp</span>: <span style="color:#66d9ef">null</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">testcm</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">init.sh</span>: |-<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> #!/bin/bash -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> CONF_FILE=&#34;/etc/sftp/users.conf&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> KEYVAULT=&#34;Insert name of Key Vault&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_ID=&#34;Insert service principal Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_PASSWORD=&#34;Insert service principal password&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_TENANT_ID=&#34;Insert Az AAD Tenant Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SUBSCRIPTION_ID=&#34;Insert Az Subscription Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az login --service-principal --username &#34;${AZ_SPN_ID}&#34; --password &#34;${AZ_SPN_PASSWORD}&#34; --tenant &#34;${AZ_SPN_TENANT_ID}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az account set --subscription &#34;${AZ_SUBSCRIPTION_ID}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETS+=($(az keyvault secret list --vault-name $KEYVAULT --query &#34;[].id&#34; -o tsv)) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> chmod 755 /home -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [[ -e $CONF_FILE ]]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> rm -rf &#34;${CONF_FILE}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> touch $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> else -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> touch $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> for SECRET in &#34;${SECRETS[@]}&#34;; do -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETNAME=$(basename $SECRET | tr -d &#39;\r&#39;) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETVALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $SECRETNAME --query &#39;value&#39; | tr -d &#39;&#34;&#39; | tr -d &#39;\r&#39;) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;$SECRETNAME:$SECRETVALUE:::upload&#34; &gt;&gt; $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> done -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [[ ! -s $CONF_FILE ]]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;** ERROR: user.conf is empty&#34; 1&gt;&amp;2 -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> exit 1 -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi</span> -</span></span></code></pre></div><p>The initContainer will use this configMap to read secrets from an Azure Key Vault and then write the secrets to the users.conf file. The users.conf file contains user account information. In the Key Vault, the secret name should be the username and the secret value should be the password. This Key Vault must exist and contain the secrets prior to deploying this solution.</p> -<p>When I deployed this solution in my environment, I used an Azure DevOps pipeline to create/manage the Key Vault with Terraform and then deploy the secrets using an inline Powershell script. However, this is beyond the scope of this article, and I will not be covering it here. You will also need to create a Service Principal in your AAD tenant and grant it access to the Key Vault. The Service Principal needs to have at least read access to the Key Vault.</p> -<p>Before deploying the configMap, you need to fill in values for these variables:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span> KEYVAULT<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert name of Key Vault&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert service principal Id&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_PASSWORD<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert service principal password&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_TENANT_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert Az AAD Tenant Id&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SUBSCRIPTION_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert Az Subscription Id&#34;</span> -</span></span></code></pre></div><p>These values pertain to the service principal with read access to the Key Vault. After filling out these variables, you can deploy the configMap using kubectl.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl create -f configmap.yaml -</span></span></code></pre></div><p>You can deploy the PVC using this yaml file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">azurefile-csi-nfs</span> -</span></span></code></pre></div><p>When creating the persistent volume claim for the deployment, you specify azurefile-csi-nfs as the StorageClass. This will create an NFSv4 share in a premium storage account. The reclaim policy of the storage class ensures that the file share is deleted when the associated Persistent Volume is deleted. Change the reclaim policy to “Retain” if you want the file shares to persist after deleting the PV. Furthermore, the storage class enables the file share to be expandable by modifying the storage request size on the PVC.</p> -<p>After deploying the PVC, you can verify its existence by running:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl get pvc -</span></span></code></pre></div><p>You should see output similar to the following (the manifest for the replicaSet is by far the most complicated of all the code referenced here):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Deployment</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">matchLabels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">strategy</span>: {} -</span></span><span style="display:flex;"><span> <span style="color:#f92672">template</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initContainer</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">chmodder</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">mcr.microsoft.com/azure-cli</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">command</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">/bin/sh</span> -</span></span><span style="display:flex;"><span> - -<span style="color:#ae81ff">c</span> -</span></span><span style="display:flex;"><span> - <span style="color:#e6db74">&#34;/scripts/init.sh&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/scripts</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">docker.io/atmoz/sftp:alpine</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">imagePullPolicy</span>: <span style="color:#ae81ff">IfNotPresent</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;64Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;250m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">limits</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;128Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;500m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">livenessProbe</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tcpSocket</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initialDelaySeconds</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">timeoutSeconds</span>: <span style="color:#ae81ff">5</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">periodSeconds</span>: <span style="color:#ae81ff">10</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">failureThreshold</span>: <span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readinessProbe</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tcpSocket</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initialDelaySeconds</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">timeoutSeconds</span>: <span style="color:#ae81ff">5</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">periodSeconds</span>: <span style="color:#ae81ff">10</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">failureThreshold</span>: <span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/home</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/etc/sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">dnsPolicy</span>: <span style="color:#ae81ff">ClusterFirst</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">restartPolicy</span>: <span style="color:#ae81ff">Never</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">configMap</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">emptyDir</span>: {} -</span></span></code></pre></div><p>You may need to change the CPU/memory requests and limits. These values worked for me, but your results may vary. You can also add/change the labels as you see fit.</p> -<p>This will handle routing traffic to our pods.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Service</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp-service</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">LoadBalancer</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">ports</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">protocol</span>: <span style="color:#ae81ff">TCP</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">targetPort</span>: <span style="color:#ae81ff">22</span> -</span></span></code></pre></div><p>Users will be connected in a round-robin fashion to the pods. This manifest will create a service of type LoadBalancer. Which will in turn create a new public Azure Load Balancer in the resource group that contains your Azure Kubernetes Service cluster if one does not already exist. If you already have a public load balancer, a new frontend IP address will be added.</p> -<p>That’s all for now. Please feel free to contact me if you have any questions.</p> - + http://localhost:1313/posts/2022-01-16-azure-kubernetes-sftp-solution/ + In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault. Here is the link to my Github account where you can download the code mentioned in this article: https://github.com/rnemeth90/kubernetes-sftp We will work through the following steps in this article: - Continuous Deployment Models - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ + http://localhost:1313/posts/2022-01-14-continuous-deployment-models/ Fri, 14 Jan 2022 19:24:01 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ - <p>When deploying new software releases to servers or (insert -as-a-service&gt; here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments.</p> -<h2 id="bluegreen-deployments" >Blue/Green Deployments -<span> - <a href="#bluegreen-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. Instead, it gets deployed to another set of servers (blue) first. Since the blue servers are not currently serving any traffic for users, the deployment has no impact. However, once the deployment has been completed successfully and tested, users will be directed to the new deployment (blue). You can control all user traffic or a subset of user traffic if your load balancer supports it (referred to as ‘Progressive Exposure’).</p> -<p>The next release will then repeat the same process. Blue would be the current production environment, so you would first deploy to the green servers. This model requires two sets of identical hosts and a load balancer or reverse proxy in front of them. If there are any unexpected issues with the new release, it is straightforward to switch back to the previous release. The disadvantage to this type of model is that it requires having redundant environments (and potentially wasted resources). However, this is less of a concern if using container orchestration platforms such as Kubernetes.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/01/2022-01-19_07h57_58-1024x575.png" alt="Blue Green deployment model"></p> -<h2 id="immutable-servers" >Immutable Servers -<span> - <a href="#immutable-servers"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>There is an alternative method of blue/green deployments called “immutable servers”. This method is identical to blue/green deployments as described above. However, after switching user traffic over to the servers with the new release, the old servers are destroyed. They are not used again. This type of model becomes particularly efficient when using a pipeline that is capable of creating servers for you (i.e., Azure DevOps Pipelines)</p> -<h2 id="canary-deployments" >Canary Deployments -<span> - <a href="#canary-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>In a canary deployment, not all users are routed to the new release immediately. Only a limited percentage of users get access to the new release. These users are the canaries. They should be monitored closely, so it is important to be using Not all users are routed to the new release immediately in a canary deployment. Only a limited percentage of users get access to the latest release. These users are the canaries.</p> -<p>Organizations should monitor the canaries closely, so it is essential to be using monitoring software capable of looking at the statistics of a web application from the users’ perspective (for example, Application Insights). The number of canaries can increase until all traffic is directed to the new release over time. The most significant advantage of this method is limited exposure to issues. If a problem appears after the release is deployed, only a small subset of users will experience it. After you fix the issues and redeploy the release, it’s best to select a different group of users to be canaries.</p> -<h2 id="ring-based-deployments" >Ring Based Deployments -<span> - <a href="#ring-based-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>A ring-based deployment has multiple production environments. Each serves a limited number of users, similar to a canary deployment. However, you can have as many production environments as you want with a ring-based deployment. New releases are deployed to the rings one by one over time.</p> -<h2 id="feature-flag-deployments" >Feature Flag Deployments -<span> - <a href="#feature-flag-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Feature flags are used to expose new features to sets of users slowly. Unlike the other deployment models, they are not implemented in the infrastructure. Instead, they are typically implemented and enabled in code or database. An example would be a feature flag in a database that gives users access to a button on your web page. A developer could enable the flag for a set of users. These users would be able to see the button; other users would not. Feature flags can even toggle bug fixes or performance improvements.</p> -<p>I will cover implementing blue/green deployments in Azure using Azure DevOps and App Services in a future article.</p> - + http://localhost:1313/posts/2022-01-14-continuous-deployment-models/ + When deploying new software releases to servers or (insert -as-a-service&gt; here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments. Blue/Green Deployments Link to heading Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. - Deploy Azure VMs Using Azure Devops CI/CD Pipeline - https://rnemeth90.github.io/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ + http://localhost:1313/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ Fri, 14 Jan 2022 18:46:35 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ - <p>This article assumes that you have already created a pipeline in Azure Devops and have it linked to an Azure Devops repo. You will need to create a variable named $vmpassword and assign it the value stored in your key vault.</p> -<p>To create a release pipeline that will automatically create a VM (using the password stored in key vault for the local administrator account), do the following:</p> -<ol> -<li>Create a new release pipeline</li> -</ol> -<p><img src="https://www.rnemeth90.github.io/content/images/2021/01/image-13.png" alt=""></p> -<p>3. In the “select a template” box, choose “Empty Job”<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-14.png" alt=""></p> -<p>4. Select “Tasks” in the navigation bar, and then select the appropriate stage. For simplicities sake, we will be using 1 stage within this release.<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-15.png" alt=""></p> -<p>5. Click on the “+” in the Agent job bar, and then in the “Add tasks” section, type in “Key Vault”. Click “Azure Key Vault” and then click “Add”. <img src="https://www.rnemeth90.github.io/content/images/2021/01/image-16.png" alt=""></p> -<p>6. Click on the “Azure Key Vault:” task to configure it. Select your subscription, Key Vault, and the secrets filter. You can also create the $vmpassword variable as a variable within your devops project, rather than assigning it as a secret filter for the release. <img src="https://www.rnemeth90.github.io/content/images/2021/01/image-20.png" alt=""></p> -<p>7. In your Key Vault, you need to grant the devops account access to the Key Vault. To do this, go to your Key Vault and create a new access policy. This policy will be assigned to a service principal that is being used by your Azure Devops project. To find the ID of this service principal, go to your project settings, and under “Pipelines”, click on “Service Connections”. Then select the service connection that resembles your subscription. After doing this, click “Manage Service Principal”. In the service principal window, click “Manifest” and then find the “name” tag within the JSON.<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-19.png" alt=""></p> -<p>8. Now go back to your key vault, and assign an access policy for this service principal. Grant the principal read and list for secrets.</p> -<p>9. Add another agent job for the task (see step 6) and search for “azure cli”. Click on “Add” for Azure CLI. Configure the settings for this job as below:<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-18.png" alt=""></p> -<p>10. Save and run your pipeline. Give it some time to complete, and go take a look at your newly created VM. This is just a very simple example of creating a server as part of a CI/CD pipeline. You can then deploy your code to it, run some tests, destroy them VM, etc. Completely automated.<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-21.png" alt=""></p> - + http://localhost:1313/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ + This article assumes that you have already created a pipeline in Azure Devops and have it linked to an Azure Devops repo. You will need to create a variable named $vmpassword and assign it the value stored in your key vault. To create a release pipeline that will automatically create a VM (using the password stored in key vault for the local administrator account), do the following: Create a new release pipeline 3. - Azure Devops &#8211; Self Hosted Agent Service Won&#8217;t Start &#8211; Incorrect Function - https://rnemeth90.github.io/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ + http://localhost:1313/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ Fri, 14 Jan 2022 18:45:00 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ - <p>I setup a self hosted agent for Azure Devops this morning on Server 2012 R2 (legacy Visual Studio dependencies…) and found that I was unable to start the service. The error I received was “Error 1 Incorrect Function” when attempting to start the service in services.msc.</p> -<p>I was attempting to run the agent from within my user profile downloads folder. I originally was not aware the service would be running from this directory. I thought it would copy its binary files to program files directory or programdata, like 99% of all other apps. The service installs and attempts to run itself as the “network service” authority. This account does not have permission to a user profile folder by default, and the installation script is not able to grant it permission for some reason (I didn’t investigate this further). I removed the agent, moved the installation files to the root of c:, and then reinstalled. The agent service is now able to start successfully.</p> - + http://localhost:1313/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ + I setup a self hosted agent for Azure Devops this morning on Server 2012 R2 (legacy Visual Studio dependencies…) and found that I was unable to start the service. The error I received was “Error 1 Incorrect Function” when attempting to start the service in services.msc. I was attempting to run the agent from within my user profile downloads folder. I originally was not aware the service would be running from this directory. - Exam AZ-303: Microsoft Azure Architect Technologies Study Guide - https://rnemeth90.github.io/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ + http://localhost:1313/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ Wed, 16 Dec 2020 14:44:00 +0000 - - https://rnemeth90.github.io/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ - <p><span style="font-family: arial;">I recently passed the AZ-303 exam. Below are some of the resources I used to prepare for the exam. In addition to the links below, I also used Alan Rodrigues’ course on Udemy. </span></p> -<p><span style="font-family: arial;"><a href="https://www.udemy.com/course/az-102-azure-administrator-certification-transition/">https://www.udemy.com/course/az-102-azure-administrator-certification-transition/</a> -</span></p> -<p><span style="font-family: arial;">The Udemy course and Microsoft Docs are enough to pass the exam. The course has some good practice exams and labs that align well with what you’ll see on the real exam regarding difficulty. I was scoring in the high 90’s on the Udemy exams. On the real exam, my score was 923. So, I think, if you comprehend the material well, and get high scores on Udemy practice exams, you’ll do well on the real exam.</span></p> -<p><span style="font-family: arial;">Just wanted to share my experience, hopefully it helps.</span></p> -<p><strong><u><span style="font-size: large;">Implement and Monitor an Azure Infrastructure (50-55%)</span></u></strong></p> -<p><span style="font-size: medium;"><strong>Implement cloud infrastructure monitoring</strong></span></p> -<ul> -<li> -<p>monitor security</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/security-center/security-center-introduction">What is Azure Security Center?</a></p> -</li> -<li> -<p>monitor performance</p> -</li> -<li> -<p>configure diagnostic settings on resources</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/diagnostic-settings">Create diagnostic settings to send platform logs and metrics to different destinations</a></p> -</li> -<li> -<p>create a performance baseline for resources</p> -</li> -<li> -<p><a href="https://cloudacademy.com/course/analyzing-resource-utilization-azure/resource-baseline/">Analyzing Resource Utilization on Azure</a></p> -</li> -<li> -<p>monitor for unused resources</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cost-management-billing/costs/quick-acm-cost-analysis?tabs=azure-portal">Quickstart: Explore and analyze costs with cost analysis</a></p> -</li> -<li> -<p>monitor performance capacity</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/insights/vminsights-performance">How to chart performance with Azure Monitor for VMs</a></p> -</li> -<li> -<p>visualize diagnostics data using Azure Monitor</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/workbooks-overview">Azure Monitor Workbooks</a></p> -</li> -<li> -<p>monitor health and availability</p> -</li> -<li> -<p>monitor networking</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/insights/network-insights-overview">Azure Monitor for Networks</a></p> -</li> -<li> -<p>monitor service health</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/service-health/service-health-overview">Service Health overview</a></p> -</li> -<li> -<p>monitor cost</p> -</li> -<li> -<p>monitor spend</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cost-management-billing/costs/quick-acm-cost-analysis?tabs=azure-portal">Quickstart: Explore and analyze costs with cost analysis</a></p> -</li> -<li> -<p>report on spend</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cost-management-billing/understand/download-azure-invoice">View and download your Microsoft Azure invoice</a></p> -</li> -<li> -<p>configure advanced logging</p> -</li> -<li> -<p>implement and configure Azure Monitor insights, including App Insights, Networks, Containers</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/monitor-reference">What is monitored by Azure Monitor?</a></p> -</li> -<li> -<p>configure a Log Analytics workspace</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/learn/quick-create-workspace">Create a Log Analytics workspace in the Azure portal</a></p> -</li> -<li> -<p>configure logging for workloads</p> -</li> -<li> -<p>initiate automated responses by using Action Groups</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/action-groups">Create and manage action groups in the Azure portal</a></p> -</li> -<li> -<p>configure and manage advanced alerts</p> -</li> -<li> -<p>collect alerts and metrics across multiple subscriptions</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/alerts-metric">Create, view, and manage metric alerts using Azure Monitor</a></p> -</li> -<li> -<p>view Alerts in Azure Monitor logs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/alerts-activity-log">Create, view, and manage activity log alerts by using Azure Monitor</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement storage accounts</span></strong></p> -<ul> -<li> -<p>select storage account options based on a use case</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-account-create?tabs=azure-portal">Create a storage account</a></p> -</li> -<li> -<p>configure Azure Files and blob storage</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/files/storage-how-to-create-file-share?tabs=azure-portal">Create an Azure file share</a></p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-portal">Quickstart: Upload, download, and list blobs with the Azure portal</a></p> -</li> -<li> -<p>configure network access to the storage account</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-network-security">Configure Azure Storage firewalls and virtual networks</a></p> -</li> -<li> -<p>implement Shared Access Signatures and access policies</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-sas-overview">Grant limited access to Azure Storage resources using shared access signatures (SAS)</a></p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/rest/api/storageservices/define-stored-access-policy">Define a stored access policy</a></p> -</li> -<li> -<p>implement Azure AD authentication for storage</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-auth-aad">Authorize access to blobs and queues using Azure Active Directory</a></p> -</li> -<li> -<p>manage access keys</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-account-keys-manage?tabs=azure-portal">Manage storage account access keys</a></p> -</li> -<li> -<p>implement Azure storage replication</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/blobs/object-replication-configure?tabs=portal">Configure object replication for block blobs</a></p> -</li> -<li> -<p>implement Azure storage account failover</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-disaster-recovery-guidance">Disaster recovery and storage account failover</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement VMs for Windows and Linux</span></strong></p> -<ul> -<li> -<p>configure High Availability</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/manage-availability">Manage the availability of Linux virtual machines</a></p> -</li> -<li> -<p>configure storage for VMs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/managed-disks-overview">Introduction to Azure managed disks</a></p> -</li> -<li> -<p>select virtual machine size</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/sizes">Sizes for virtual machines in Azure</a></p> -</li> -<li> -<p>implement Azure Dedicated Hosts</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/dedicated-hosts-portal">Deploy VMs and scale sets to dedicated hosts using the portal</a></p> -</li> -<li> -<p>deploy and configure scale sets</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machine-scale-sets/quick-create-portal">Quickstart: Create a virtual machine scale set in the Azure portal</a></p> -</li> -<li> -<p>configure Azure Disk Encryption</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/windows/disk-encryption-overview">Azure Disk Encryption for Windows VMs</a></p> -</li> -</ul> -<p><span style="font-size: medium;"><strong>Automate deployment and configuration of resources</strong></span></p> -<ul> -<li> -<p>save a deployment as an Azure Resource Manager template</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/export-template-portal">Single and multi-resource export to a template in Azure portal</a></p> -</li> -<li> -<p>modify Azure Resource Manager template</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/overview">What are ARM templates?</a></p> -</li> -<li> -<p>evaluate location of new resources</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/view-activity-logs">View activity logs to monitor actions on resources</a></p> -</li> -<li> -<p>configure a virtual disk template</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/windows/capture-image-resource">Create a managed image of a generalized VM in Azure</a></p> -</li> -<li> -<p>deploy from a template</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/deploy-vms-from-vhd-templates/">Deploy Azure virtual machines from VHD templates</a></p> -</li> -<li> -<p>manage a template library</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/shared-image-galleries">Shared Image Galleries overview</a></p> -</li> -<li> -<p>create and execute an automation runbook</p> -</li> -<li> -<p><a href="https://azure.microsoft.com/en-us/blog/azure-automation-runbook-management/">Getting Started With Azure Automation – Runbook Management</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement virtual networking</span></strong></p> -<ul> -<li> -<p>implement VNet to VNet connections</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/vpn-gateway/vpn-gateway-howto-vnet-vnet-resource-manager-portal">Configure a VNet-to-VNet VPN gateway connection by using the Azure portal</a></p> -</li> -<li> -<p>implement VNet peering</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-peering-overview">Virtual network peering</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement Azure Active Directory</span></strong></p> -<ul> -<li> -<p>add custom domains</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/add-custom-domain">Add your custom domain name using the Azure Active Directory portal</a></p> -</li> -<li> -<p>configure Azure AD Identity Protection</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/identity-protection/overview-identity-protection">What is Identity Protection?</a></p> -</li> -<li> -<p>implement self-service password reset</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/tutorial-enable-sspr">Tutorial: Enable users to unlock their account or reset passwords using Azure Active Directory self-service password reset</a></p> -</li> -<li> -<p>implement Conditional Access including MFA</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/conditional-access/howto-conditional-access-policy-all-users-mfa">Conditional Access: Require MFA for all users</a></p> -</li> -<li> -<p>configure user accounts for MFA</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-userstates">Enable per-user Azure AD Multi-Factor Authentication to secure sign-in events</a></p> -</li> -<li> -<p>configure fraud alerts</p> -</li> -<li> -<p><a href="Enable%20per-user%20Azure%20AD%20Multi-Factor%20Authentication%20to%20secure%20sign-in%20events">Fraud alert</a></p> -</li> -<li> -<p>configure bypass options</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-server-settings#one-time-bypass">One-time bypass</a></p> -</li> -<li> -<p>configure Trusted IPs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-mfasettings#trusted-ips">Trusted IPs</a></p> -</li> -<li> -<p>configure verification methods</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/concept-sspr-howitworks#authentication-methods">Authentication methods</a></p> -</li> -<li> -<p>implement and manage guest accounts</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/external-identities/b2b-quickstart-add-guest-users-portal">Quickstart: Add guest users to your directory in the Azure portal</a></p> -</li> -<li> -<p>manage multiple directories</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/enterprise-users/licensing-directory-independence">Understand how multiple Azure Active Directory organizations interact</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement and manage hybrid identities</span></strong></p> -<ul> -<li> -<p>install and configure Azure AD Connect</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-install-express">Getting started with Azure AD Connect using express settings</a></p> -</li> -<li> -<p>identity synchronization options</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/plan-connect-user-signin">Azure AD Connect user sign-in options</a></p> -</li> -<li> -<p>configure and manage password sync and password writeback</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/tutorial-enable-sspr-writeback">Tutorial: Enable Azure Active Directory self-service password reset writeback to an on-premises environment</a></p> -</li> -<li> -<p>configure single sign-on</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-sso-quick-start">Azure Active Directory Seamless Single Sign-On: Quickstart</a></p> -</li> -<li> -<p>use Azure AD Connect Health</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/whatis-azure-ad-connect#what-is-azure-ad-connect-health">What is Azure AD Connect Health?</a></p> -</li> -</ul> -<p><strong><u><span style="font-size: large;">Implement Management and Security Solutions (25-30%)</span></u></strong></p> -<p><span style="font-size: medium;"><strong>Manage workloads in Azure</strong></span></p> -<ul> -<li> -<p>migrate workloads using Azure Migrate</p> -</li> -<li> -<p>assess infrastructure</p> -</li> -<li> -<p>select a migration method</p> -</li> -<li> -<p>prepare the on-premises for migration</p> -</li> -<li> -<p>recommend target infrastructure</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/migrate/tutorial-migrate-hyper-v">Migrate Hyper-V VMs to Azure</a></p> -</li> -<li> -<p>implement Azure Backup for VMs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/backup/backup-azure-vms-first-look-arm">Back up an Azure VM from the VM settings</a></p> -</li> -<li> -<p>implement disaster recovery</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/site-recovery/azure-to-azure-tutorial-enable-replication">Tutorial: Set up disaster recovery for Azure VMs</a></p> -</li> -<li> -<p>implement Azure Update Management</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/automation/update-management/enable-from-vm">Enable Update Management for an Azure VM</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement load balancing and network security</span></strong></p> -<ul> -<li> -<p>implement Azure Load Balancer</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/load-balancer/load-balancer-overview">What is Azure Load Balancer?</a></p> -</li> -<li> -<p>implement an application gateway</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/application-gateway/overview">What is Azure Application Gateway?</a></p> -</li> -<li> -<p>implement a Web Application Firewall</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/web-application-firewall/overview">What is Azure Web Application Firewall?</a></p> -</li> -<li> -<p>implement Azure Firewall</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/firewall/overview">What is Azure Firewall?</a></p> -</li> -<li> -<p>implement the Azure Front Door Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/frontdoor/quickstart-create-front-door">Quickstart: Create a Front Door for a highly available global web application</a></p> -</li> -<li> -<p>implement Azure Traffic Manager</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/traffic-manager/traffic-manager-overview">What is Traffic Manager?</a></p> -</li> -<li> -<p>implement Network Security Groups and Application Security Groups</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-network/network-security-groups-overview">Network security groups</a></p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-network/application-security-groups">Application security groups</a></p> -</li> -<li> -<p>implement Bastion</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/bastion/">Azure Bastion documentation</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement and manage Azure governance solutions</span></strong></p> -<ul> -<li> -<p>create and manage hierarchical structure that contains management groups</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/governance/management-groups/overview">What are Azure management groups?</a></p> -</li> -<li> -<p>subscriptions and resource groups</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-setup-guide/organize-resources?tabs=AzureManagementGroupsAndHierarchy">Organize your Azure resources effectively</a></p> -</li> -<li> -<p>assign RBAC roles</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal">Add or remove Azure role assignments using the Azure portal</a></p> -</li> -<li> -<p>create a custom RBAC role</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/custom-roles">Azure custom roles</a></p> -</li> -<li> -<p>configure access to Azure resources by assigning roles</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal">Add or remove Azure role assignments using the Azure portal</a></p> -</li> -<li> -<p>configure management access to Azure</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/manage-subscription-access-azure-rbac/">Manage access to an Azure subscription by using Azure role-based access control (RBAC)</a></p> -</li> -<li> -<p>interpret effective permissions</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/check-access">Quickstart: Check access for a user to Azure resources</a></p> -</li> -<li> -<p>set up and perform an access review</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/governance/access-reviews-overview">What are Azure AD access reviews?</a></p> -</li> -<li> -<p>implement and configure an Azure Policy</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/governance/policy/assign-policy-portal">Quickstart: Create a policy assignment to identify non-compliant resources</a></p> -</li> -<li> -<p>implement and configure an Azure Blueprint</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/governance/blueprints/overview">What is Azure Blueprints?</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Manage security for applications</span></strong></p> -<ul> -<li> -<p>implement and configure KeyVault</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/configure-and-manage-azure-key-vault/">Configure and manage secrets in Azure Key Vault</a></p> -</li> -<li> -<p>implement and configure Managed Identities</p> -</li> -<li> -<p><a href="https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=18fbca16-2224-45f6-85b0-f7bf2b39b3f3&amp;nonce=ef221978-b465-49a1-9226-e8a0e4d25480&amp;prompt=none&amp;redirect_uri=https%3A%2F%2Fdocs.microsoft.com%2F_themes%2Fdocs.theme%2Fmaster%2Fen-us%2F_themes%2Fglobal%2Fsign-in.html&amp;response_mode=fragment&amp;response_type=id_token&amp;scope=openid%20profile&amp;sso_reload=true&amp;state=silent%3A%2F%2Fhttps%3A%2F%2Fdocs.microsoft.com&amp;fromOrigin=https%3A%2F%2Fdocs.microsoft.com&amp;iframe-request-id=685d3411-99a9-4f94-81e4-d9b8af575600">What are managed identities for Azure resources?</a></p> -</li> -<li> -<p>register and manage applications in Azure AD</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app">Quickstart: Register an application with the Microsoft identity platform</a></p> -</li> -</ul> -<p><strong><u><span style="font-size: large;">Implement Solutions for Apps (10-15%)</span></u></strong></p> -<p><strong><span style="font-size: medium;">Implement an application infrastructure</span></strong></p> -<ul> -<li> -<p>create and configure Azure App Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/quickstart-dotnetcore?tabs=netcore31&amp;pivots=platform-linux">Quickstart: Create an ASP.NET Core web app in Azure</a></p> -</li> -<li> -<p>create an App Service Web App for Containers</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/deploy-run-container-app-service/">Deploy and run a containerized web app with Azure App Service</a></p> -</li> -<li> -<p>create and configure an App Service plan</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/app-service-plan-manage">Manage an App Service plan in Azure</a></p> -</li> -<li> -<p>configure an App Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/configure-common">Configure an App Service app in the Azure portal</a></p> -</li> -<li> -<p>configure networking for an App Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/web-sites-integrate-with-vnet">Integrate your app with an Azure virtual network</a></p> -</li> -<li> -<p>create and manage deployment slots</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/deploy-staging-slots">Set up staging environments in Azure App Service</a></p> -</li> -<li> -<p>implement Logic Apps</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/logic-apps/quickstart-create-first-logic-app-workflow">Quickstart: Create your first Logic Apps workflow – Azure portal</a></p> -</li> -<li> -<p>implement Azure Functions</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-azure-function">Create your first function in the Azure portal</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement container-based applications </span></strong></p> -<ul> -<li> -<p>create a container image</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/container-registry/container-registry-quickstart-task-cli">Quickstart: Build and run a container image using Azure Container Registry Tasks</a></p> -</li> -<li> -<p>configure Azure Kubernetes Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/aks/kubernetes-walkthrough-portal">Quickstart: Deploy an Azure Kubernetes Service (AKS) cluster using the Azure portal</a></p> -</li> -<li> -<p>publish and automate image deployment to the Azure Container Registry</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/container-instances/container-instances-using-azure-container-registry">Deploy to Azure Container Instances from Azure Container Registry</a></p> -</li> -<li> -<p>publish a solution on an Azure Container Instance</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/container-instances/container-instances-quickstart-portal">Quickstart: Deploy a container instance in Azure using the Azure portal</a></p> -</li> -</ul> -<p><strong><u>Implement and Manage Data Platforms (10-15%)</u></strong></p> -<p><strong><span style="font-size: medium;">Implement NoSQL databases</span></strong></p> -<ul> -<li> -<p>configure storage account tables</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/tables/table-storage-quickstart-portal">Quickstart: Create an Azure Storage table in the Azure portal</a></p> -</li> -<li> -<p>select appropriate CosmosDB APIs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/choose-api-for-cosmos-db/">Choose the appropriate API for Azure Cosmos DB</a></p> -</li> -<li> -<p>set up replicas in CosmosDB</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cosmos-db/distribute-data-globally">Distribute your data globally with Azure Cosmos DB</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement Azure SQL databases</span></strong></p> -<ul> -<li> -<p>configure Azure SQL database settings</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-sql/database/single-database-create-quickstart?tabs=azure-portal">Quickstart: Create an Azure SQL Database single database</a></p> -</li> -<li> -<p>implement Azure SQL Database managed instances</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-sql/managed-instance/sql-managed-instance-paas-overview">What is Azure SQL Managed Instance?</a></p> -</li> -<li> -<p>configure HA for an Azure SQL database</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-sql/database/high-availability-sla">High availability for Azure SQL Database and SQL Managed Instance</a></p> -</li> -<li> -<p>publish an Azure SQL database</p> -</li> -</ul> - + http://localhost:1313/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ + I recently passed the AZ-303 exam. Below are some of the resources I used to prepare for the exam. In addition to the links below, I also used Alan Rodrigues’ course on Udemy. https://www.udemy.com/course/az-102-azure-administrator-certification-transition/ The Udemy course and Microsoft Docs are enough to pass the exam. The course has some good practice exams and labs that align well with what you’ll see on the real exam regarding difficulty. I was scoring in the high 90’s on the Udemy exams. - Azure AD Sync &#8211; Set-MsolDirSyncEnabled : You cannot turn off Active Directory synchronization. - https://rnemeth90.github.io/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ + http://localhost:1313/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ Thu, 26 Nov 2020 16:31:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ - <p>I recently ran into a situation in my lab environment that required I resync all (2000+) user accounts to Azure AD. Though this sounds complex and daunting, its actually quite simple. T</p> -<p>The basic steps involve disabling sync, and then removing the user objects. This can all be done with two PowerShell commands:</p> -<p>1) Set-MsolDirSyncEnabled -EnableDirSync $false</p> -<p><a href="https://lh3.googleusercontent.com/-rGK18FXw7ns/X7_WthQR0CI/AAAAAAAAyCM/gg7MsY2fcVIcWMMbvxYzPpbpPyKwgHP8ACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image.png" alt=""></a></p> -<p>2) Get-MsolUser -All | Remove-MsolUser -force</p> -<p><a href="https://lh3.googleusercontent.com/-miyfN7OISGo/X7_WzDCc6iI/AAAAAAAAyCQ/PtHURTTVMQ4uypzO7L1UaLfyEs0fpYGdACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-1.png" alt=""></a></p> -<p>The account that you are currently running the commands as will not be removed.</p> -<p>To enable Azure AD Sync, you simply reverse the boolean operation on the Set-MsolDirSyncEnabled cmdlet above. However, I ran into an issue when trying to enable Azure AD Sync.</p> -<p><a href="https://lh3.googleusercontent.com/-R1TPVgYaEBE/X7_XM5_ljKI/AAAAAAAAyCY/VIJZnlgNEPQbhL9p3D0J3XsekBrGiNS3QCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-2.png" alt=""></a></p> -<p>After some research, it turns out you must wait a period of time (up to 12 hours in some cases) before you can make a second change to the Azure AD Sync status. This error simply means that we made a recent change to Azure AD Sync, and we must wait before making another change. To prove this, there is a “DirectorySynchronizationStatus” member for the Get-MsolCompanyInformation cmdlet. If we take a look at this member, we can see the status is “PendingDisabled”.</p> -<p><a href="https://lh3.googleusercontent.com/-0OBwKDDD5xQ/X7_X1bBxXjI/AAAAAAAAyCk/FyRlaMpCDT4aBe08TL_8sLiwUBnHkcPJQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-3.png" alt=""></a></p> -<p>Check the status of this periodically over the next 12 hours or so, and once it says “Enabled” or “Disabled”, you should be able to change the state once more.</p> - + http://localhost:1313/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ + I recently ran into a situation in my lab environment that required I resync all (2000+) user accounts to Azure AD. Though this sounds complex and daunting, its actually quite simple. T The basic steps involve disabling sync, and then removing the user objects. This can all be done with two PowerShell commands: 1) Set-MsolDirSyncEnabled -EnableDirSync $false 2) Get-MsolUser -All | Remove-MsolUser -force The account that you are currently running the commands as will not be removed. - Azure VM Scale Set &#8211; Get Instance IP Address - https://rnemeth90.github.io/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ + http://localhost:1313/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ Thu, 19 Nov 2020 18:07:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ - <p>If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal.</p> -<p>There are a few options we have for retrieving information about a VMSS and its instances without using the Azure Portal. We can use PowerShell or the Azure CLI. Being that I am constantly flipping between Windows and Linux, I will detail both here.</p> -<p>You will need to have the AZ module installed. To install this module, simple open PowerShell (as admin) and type in “Install-Module -Name az”. To get the IP address of the instances within a scale set, use the following script:</p> -<p><a href="https://github.com/rnemeth90/Get-VmssInstanceIpAddress">https://github.com/rnemeth90/Get-VmssInstanceIpAddress</a></p> -<p>You can also use the Azure CLI to obtain individual instance IP addresses. This method is much simpler than PowerShell, and only requires one line of code:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>az vmss nic list –resource-group myResourceGroup –vmss-name myVmss | grep –w “privateIpAddress” -</span></span></code></pre></div> + http://localhost:1313/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ + If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal. There are a few options we have for retrieving information about a VMSS and its instances without using the Azure Portal. - Azure Policy &#8211; Allowed Locations for Resource Deployment - https://rnemeth90.github.io/posts/2020-11-17-azure-policy-allowed-locations-for/ + http://localhost:1313/posts/2020-11-17-azure-policy-allowed-locations-for/ Tue, 17 Nov 2020 17:52:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-17-azure-policy-allowed-locations-for/ - <p>Azure Policy allows us to control what actions users can perform regarding creating and managing resources in Azure. We can define policies for naming standards, require that certain extensions be installed on virtual machines, audit various resources for certain configurations… the possibilities are endless.</p> -<p>In this article, well focus on defining what locations users can deploy resources in. To get started, login to the Azure Portal and search for “Policy”.</p> -<p><a href="https://lh3.googleusercontent.com/-7ao7r-Xj5Kk/X7QNKSrY3AI/AAAAAAAAx-8/xIUtw-pRL20pSMxsOaGUwnk-9XHSpup9ACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-4.png" alt=""></a></p> -<p>Click on “Definitions”. Here you will find several built-in definitions that can be applied to your resources. Definitions are a json template containing the logic for what you want to accomplish. It is worth investing some time to look through these built-in definitions.</p> -<p>In the “search” field, type in “location”. Then, click on the “Allowed Locations” definition.</p> -<p><a href="https://lh3.googleusercontent.com/-5FJ3EcMnG8k/X7QNP-1-5II/AAAAAAAAx_A/TH4cr4SxgbQiNVdoRlDyB_F4ukOV5bJvwCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-5.png" alt=""></a></p> -<p>Here you can see the json content of the definition. The “policyRule” section is the bread and butter of the definition. In this particular example, the policyRule states that if the location that the user is deploying a resource to is NOT a) in the list of allowed locations, b) global, or c) a b2c directory, then deny the deployment.</p> -<p><a href="https://lh3.googleusercontent.com/-WKsYDX4nao4/X7QNVcSEVJI/AAAAAAAAx_E/HIbPqLSHfBIjYRRZI27X7cLjStbnXlqaQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-6.png" alt=""></a></p> -<p>Next, click on “Assign”.</p> -<p><a href="https://lh3.googleusercontent.com/-Qg35QQcnGZY/X7QNarWcMbI/AAAAAAAAx_M/Et9yP9ZNyXEU1Ow8m5BwZG8RcTBaadInQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-7.png" alt=""></a></p> -<p>You can assign the policy to a subscription or resource group. You can also create exclusions in this same window, and enable or disable the policy.</p> -<p><a href="https://lh3.googleusercontent.com/-16qmOT43oKo/X7QNfuX4KVI/AAAAAAAAx_Q/_0wak5v2CCA2yIrwLalJgvhCnBCCEJcOQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-8.png" alt=""></a></p> -<p>Click “Next”, and on the Parameters page, choose the allowed locations from the drop down menu. Then click next.</p> -<p>Azure Policy has the capability to remediate non-compliant resources. An example would be having a policy that requires anti-virus be installed on all servers. If Azure Policy detected a server that did NOT have anti-virus installed, it would use a managed identity to install AV software on the server. This particular policy does not need a remediation action, so we will just click “Next” here.</p> -<p>On the Review + Create window, review the resource and then click “Create”.</p> -<p>Back on the Azure Policy blade, select “Assignments”. We can now see that our new policy is assigned.</p> -<p><a href="https://lh3.googleusercontent.com/-K8ofsNe1ALY/X7QNrf8dfkI/AAAAAAAAx_c/3R0DRk4LKWYcGP6-LJ3vgRUcUOQaZ6r3ACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-9.png" alt=""></a></p> -<p>Back on the “Overview” page, you can track compliance for the policy. We can see here that compliance for the “Allowed Locations” policy assignment has not yet been started. This typically takes an hour or so before the compliance state is updated.</p> -<p><a href="https://lh3.googleusercontent.com/-S-zq_cWBh7Y/X7QNvjMRUrI/AAAAAAAAx_k/CG194fTLqKIHqTNMmCyJzM4W9HJ_d6aPgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-10.png" alt=""></a></p> -<p>Click on the Policy to get a more detailed view of compliance, view the definition, edit the assignment, and even create exemptions.</p> -<p><a href="https://lh3.googleusercontent.com/-9sdnYSeQZ7A/X7QNzt8EEdI/AAAAAAAAx_o/3-2_eyPVjxIFSINg8IzEhKwZzWGUgf9NQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-11.png" alt=""></a></p> - + http://localhost:1313/posts/2020-11-17-azure-policy-allowed-locations-for/ + Azure Policy allows us to control what actions users can perform regarding creating and managing resources in Azure. We can define policies for naming standards, require that certain extensions be installed on virtual machines, audit various resources for certain configurations… the possibilities are endless. In this article, well focus on defining what locations users can deploy resources in. To get started, login to the Azure Portal and search for “Policy”. - Replicate an Azure VM Image Between Regions - https://rnemeth90.github.io/posts/2020-11-03-replicate-azure-vm-image-between-regions/ + http://localhost:1313/posts/2020-11-03-replicate-azure-vm-image-between-regions/ Tue, 03 Nov 2020 20:15:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-03-replicate-azure-vm-image-between-regions/ - <p>Let’s say you have a VM in Azure North Central. You created this VM from a custom image that you maintain in an Azure image repository. Now, what if you wanted to create that same VM in Azure South Central, and use the same reference image? A standard image repository is limited to the region that it exists in. The answer here is to create a Shared Image Library, add the image to it, and then configure the image to replicate to other Azure regions.</p> -<p>This article assumes you already have an image.</p> -<p>First, create a Shared Image Gallery in Azure. Browse to the Azure portal (<a href="https://portal.azure.com/">https://portal.azure.com</a>), and (from the home page) click “create a resource”.</p> -<p><a href="https://lh3.googleusercontent.com/-LQbh5w9zFN0/X6G5qBxrC1I/AAAAAAAAx5I/QH95DqgHJzUgkC5YhWqmQ_pOXmCygVHwQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-12.png" alt=""></a></p> -<p>Search for “Shared Image Gallery” and then click “Create”.</p> -<p>Configure a subscription, resource group, and then name the Shared Image Gallery and configure what region you want it to live in. You will want to create it in the same region as your standard image repository.</p> -<p><a href="https://lh3.googleusercontent.com/-61hBPxzwPzI/X6G5w_C7-iI/AAAAAAAAx5M/GVHvFpgE2WQwupil-OSd7nZ2nJEZRI0MgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-13.png" alt=""></a></p> -<p>If you want to assign some tags to this new resource, continue to the next page. Otherwise, click “Review + Create”.</p> -<p><a href="https://lh3.googleusercontent.com/-OCPyDsSbRYo/X6G52usmBSI/AAAAAAAAx5Q/nZJuX9YZzNsWU4aJwGNkZ5kulaXb5mcGgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-14.png" alt=""></a></p> -<p>On the final page, if the validation is successful, click “Create”.</p> -<p><a href="https://lh3.googleusercontent.com/-gCwUW-ntoKA/X6G56AAogVI/AAAAAAAAx5Y/wcUUn2_P68MNl5wCWIqQTYGRqEvJMJm6QCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-15.png" alt=""></a></p> -<p>It should take less than a minute to create the shared image gallery. Once its created, click “Go to resource”.</p> -<p><a href="https://lh3.googleusercontent.com/-mZQpi2f85MQ/X6G5-7FGFUI/AAAAAAAAx5c/vPOG47n736gp87Z2rftfjvL9OcGolOGxACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-16.png" alt=""></a></p> -<p>In the shared image gallery blade, click “Add new image definition”.</p> -<p><a href="https://lh3.googleusercontent.com/-qSWGjKuUMp4/X6G6CZsRAXI/AAAAAAAAx5g/-LYCx4Qmf98k2mbjM9CC-8mKVA-zp-8rACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-17.png" alt=""></a></p> -<p>On the next page, select the region where your existing image repository lives, give the image definition a name, and then fill out the rest of the information as needed. The publisher will typically be the name of your company/organization. The offer will typically be set to the name of the overall application, being that servers typically host one piece of an application (example: database servers vs. application servers). The SKU will typically be set to the name of the component within the application (for example, a web server or database server).</p> -<p><a href="https://lh3.googleusercontent.com/-4ZaK5D-Y0FE/X6G6G3n8KsI/AAAAAAAAx5k/jd18bOcFQ1kP62-0zE1Vuhwx6WpRnEyGwCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-18.png" alt=""></a></p> -<p>Next, configure an image version. This should use the typical semantic format used in software development (major version, minor version, patch level). I will typically substitute the patch level with the date the image was captured. Probably not a best practice, but something that has served me well in the past.</p> -<p>Next, select the source image. This will be the image that you are copying from your standard image repository. You can also configure an end of life date for the image version here if you wish. In the “Target Regions” section at the bottom, select the region where you plan to create the new VM. Also select the target storage account type.</p> -<p><a href="https://lh3.googleusercontent.com/-6F59gxbQ7ws/X6G6PI4qVeI/AAAAAAAAx5w/x2SCNG8PawMUZRQS6q55kAvgsOfD8bnPACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-19.png" alt=""></a></p> -<p>You can configure some publishing options and tags on the following pages. Though, it is not required. Click “Review + create”. <span style="mso-spacerun: yes;"> </span><span style="mso-spacerun: yes;"> </span>After the validation passes, click “Create”.</p> -<p><a href="https://lh3.googleusercontent.com/-CyzD7E88UVU/X6G6TQGRu6I/AAAAAAAAx54/2yHQrYIFUp8P8JyWMuEbsfFL47UW8Il0ACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-20.png" alt=""></a></p> -<p>This process will take a few minutes to complete. Once its finished, click on “go to resource”. You now have an image that is available to be deployed in the north central region or the south central region.</p> - + http://localhost:1313/posts/2020-11-03-replicate-azure-vm-image-between-regions/ + Let’s say you have a VM in Azure North Central. You created this VM from a custom image that you maintain in an Azure image repository. Now, what if you wanted to create that same VM in Azure South Central, and use the same reference image? A standard image repository is limited to the region that it exists in. The answer here is to create a Shared Image Library, add the image to it, and then configure the image to replicate to other Azure regions. - Azure Site Recovery &#8211; VMware-to-Azure: Wrong IP address discovered for VM - https://rnemeth90.github.io/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ + http://localhost:1313/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ Tue, 21 Aug 2018 17:26:00 +0000 - - https://rnemeth90.github.io/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ - <p>When replicating virtual machines from VMware to Azure using Site Recovery, you may encounter an issue where the Configuration server discovers the wrong IP address for a VM. This can be caused by stale entries within the infrastructurevms MySQL table that is used by ASR to track VM attributes.</p> -<p>To resolve this issue, you first need to disable replication for the VM in the Azure Portal.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-21_13h20_26.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-21_13h20_26.png" alt=""></a></p> -<p>Next, login to your ASR Configuration Server and open a CMD prompt as administrator. Browse to the bin directory for your ASR installation. For example, in my case ASR is installed on the E: partition under the following directory:</p> -<p>E:\Program Files (x86)Microsoft Azure Site Recoveryhomesvsystemsbin</p> -<p>Type in this command to remove the VM from the ASR database (replace IP address with the IP of your VM):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-perl" data-lang="perl"><span style="display:flex;"><span>perl Unregister<span style="color:#f92672">-</span>ASRComponent<span style="color:#f92672">.</span>pl <span style="color:#f92672">-</span>IPAddress <span style="color:#ae81ff">10.0.0.4</span> <span style="color:#f92672">-</span>Component Source -</span></span></code></pre></div><p>That’s it. You should now be able to reconfigure replication for the VM, and ASR will discover the correct info about the VM.</p> - + http://localhost:1313/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ + When replicating virtual machines from VMware to Azure using Site Recovery, you may encounter an issue where the Configuration server discovers the wrong IP address for a VM. This can be caused by stale entries within the infrastructurevms MySQL table that is used by ASR to track VM attributes. To resolve this issue, you first need to disable replication for the VM in the Azure Portal. Next, login to your ASR Configuration Server and open a CMD prompt as administrator. - Azure AD Connect No-Start-Connection - https://rnemeth90.github.io/posts/2018-07-26-azure-ad-connect-no-start-connection/ + http://localhost:1313/posts/2018-07-26-azure-ad-connect-no-start-connection/ Thu, 26 Jul 2018 12:22:00 +0000 - - https://rnemeth90.github.io/posts/2018-07-26-azure-ad-connect-no-start-connection/ - <p>This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working.</p> -<p>After forcing the sync, I opened miisclient and noticed some strange errors. We sync multiple on-prem AD forests to Azure AD, and the status for one of them was “no-start-connection”. That error in itself does not seem significant to me. However, after clicking on the “failed-connection” link in the Connection Status pane, things became much more clear.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_05.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_05.png" alt=""></a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_18.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_18.png" alt=""></a></p> -<p>The domain controllers for the forest in question are in a datacenter that is geographically separated from the datacenter that our Azure AD Sync server lives in. The two sites are connected via a S2S VPN.</p> -<p>There was obviously some type of connection issue between our two datacenters. In my case, the issue was transient, and resolved itself after a few minutes. But if you’re experiencing this error message, check your L2/L3 connection. Also, verify DNS is working and someone didn’t make changes to your firewall(s). Just walk up or down the OSI model and you’ll eventually find the problem.</p> - + http://localhost:1313/posts/2018-07-26-azure-ad-connect-no-start-connection/ + This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working. After forcing the sync, I opened miisclient and noticed some strange errors. - Azure AD Connect Health: Latest Data is not Available in Azure Portal - https://rnemeth90.github.io/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ + http://localhost:1313/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ Wed, 18 Jul 2018 16:38:00 +0000 - - https://rnemeth90.github.io/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ - <p>I recently had to create a new Azure AD Connect server, and found that it was not able to report health status in the Azure Portal. After some troubleshooting/research, I was able to get the health status report working by registering the health agent on the server with Azure AD Health Services. Doing this involves running one PowerShell cmdlet on your AD Connect server and providing global administrator credentials.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_56.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_56.png" alt=""></a></p> -<p>First, let’s test the status of the agent communication:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_19.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_19.png" alt=""></a></p> -<p>If you do not receive any errors, that means the Azure AD Connect Health agent on your server is able to successfully communicate with the cloud service. Now, let’s register the agent:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_05.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_05.png" alt=""></a></p> -<p>You will be prompted for credentials. The credentials you provide need to be a global administrator account in your Azure AD tenant.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_42.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_42.png" alt=""></a></p> -<p>You should receive some output stating that the registration is successful (or it failed).</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h25_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h25_20.png" alt=""></a></p> -<p>Now, just go back to the Azure Portal and refresh the page. The message stating that the -“latest data is not available” should be gone.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h36_42.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h36_42.png" alt=""></a></p> - + http://localhost:1313/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ + I recently had to create a new Azure AD Connect server, and found that it was not able to report health status in the Azure Portal. After some troubleshooting/research, I was able to get the health status report working by registering the health agent on the server with Azure AD Health Services. Doing this involves running one PowerShell cmdlet on your AD Connect server and providing global administrator credentials. First, let’s test the status of the agent communication: - Removing a Forest from Azure AD Connect - https://rnemeth90.github.io/posts/2018-07-13-removing-forest-from-azure-ad-connect/ + http://localhost:1313/posts/2018-07-13-removing-forest-from-azure-ad-connect/ Fri, 13 Jul 2018 15:30:00 +0000 - - https://rnemeth90.github.io/posts/2018-07-13-removing-forest-from-azure-ad-connect/ - <p>In an organization with multiple Active Directory forests, you may want to sync objects from trusted forests. Adding trusted forests to Azure AD Sync is a simple process that I will likely cover in a future article. The focus of this post is the not-so-obvious process of removing a forest from Azure AD Connect. This can be a daunting and somewhat scary thing to do. Not fully understanding the process or having someone to guide you can leave you with thoughts like “what happens when I remove the forest from Azure AD Sync? Do on-premises objects get deleted? Are cloud objects deleted?”. I will try to answer these questions to the best of my ability and hopefully make the process simple and stress-free for you.</p> -<p>To get started, we first need to open PowerShell and disable the AD Sync scheduler. You can do this by running the “Set-ADSyncScheduler” cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h47_05.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h47_05.png" alt=""></a></p> -<p>This cmdlet is included in the ADSync PowerShell module. You may need to load the module prior to using the cmdlet:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Import-Module ADSync -</span></span></code></pre></div><p>The next step is to open FIM (miisclient) located in the install directory of Microsoft Azure AD Sync. By default, this is C:Program FilesMicrosoft Azure AD SyncUIShellmiisclient.exe. Once you have FIM open, click on the Connectors tab, then right click on the connector for the forest that you want to delete, and click “Delete”.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_26.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_26.png" alt=""></a></p> -<p>You will then be prompted, asking if you want to just delete the Connector Space, or delete the Connector and the Connector Space. The former open removes all data, but keeps the configuration in case you want to use it again later. The latter option deleted the data and the configuration. This open should only be used if you don’t plan on syncing the forest again.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_09.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_09.png" alt=""></a></p> -<p>The connector for the forest is now deleted, but what actually happens? Your on-premises objects do not get removed for the forest, and cloud objects <strong>are</strong> removed. Simple enough, right?</p> -<p>Now you just need to re-enable the AD Sync Scheduler with this cmdlet:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Set-ADSyncScheduler -SyncCycleEnabled $true -</span></span></code></pre></div><p>One last thing to mention… You may receive an email from the Microsoft Online Services Team stating that the identity synchronization failed due to a deletion threshold being met. By default, Azure AD Connect will not allow you to delete more than 500 objects in your cloud directory. This is to protect you from making a careless (potentially resume generating) mistake. The email will look something like this:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h56_04.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h56_04.png" alt=""></a></p> -<p>If you are certain that you want to proceed with deleting the objects, here are the steps:</p> -<ol> -<li> -<p>Disable the deletion threshold protection. Open PowerShell on your Azure AD Sync server and type in this cmdlet: Disable-ADSyncExportDeletionThreshold. You will be prompted for credentials, sign-in with an Azure AD Global Admin account.</p> -</li> -<li> -<p>Open FIM (miisclient), and click on the “Connectors” button at the top of the window. Right click on the connector of type “Windows Azure Active Directory”, and select “Run…”.</p> -</li> -</ol> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_39.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_39.png" alt=""></a></p> -<ol start="3"> -<li>Next, click Export and then click Ok.</li> -</ol> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_58.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_58.png" alt=""></a></p> -<ol start="4"> -<li> -<p>Allow the connector to run. This will take a few minutes. You can monitor the progress by clicking the Operations button.</p> -</li> -<li> -<p>Once this completes, you need to re-enable the deletion threshold. You can do this by running this cmdlet: <span style="background: #F9F9F9;"></p> -</li> -</ol> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Enable-ADSyncExportDeletionThreshold -DeletionThreshold <span style="color:#ae81ff">500</span>. -</span></span></code></pre></div><p>You will be prompted for credentials again. Just type in your Azure AD Global Admin creds. You can even lower the threshold if you’d like. I set mine to 100.</p> - + http://localhost:1313/posts/2018-07-13-removing-forest-from-azure-ad-connect/ + In an organization with multiple Active Directory forests, you may want to sync objects from trusted forests. Adding trusted forests to Azure AD Sync is a simple process that I will likely cover in a future article. The focus of this post is the not-so-obvious process of removing a forest from Azure AD Connect. This can be a daunting and somewhat scary thing to do. Not fully understanding the process or having someone to guide you can leave you with thoughts like “what happens when I remove the forest from Azure AD Sync? - Error When Reinstalling DirSync - https://rnemeth90.github.io/posts/2015-08-13-error-when-reinstalling-dirsync/ + http://localhost:1313/posts/2015-08-13-error-when-reinstalling-dirsync/ Thu, 13 Aug 2015 18:59:00 +0000 - - https://rnemeth90.github.io/posts/2015-08-13-error-when-reinstalling-dirsync/ - <p>Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process:</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2015/08/1.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/1.png" alt=""></a></p> -<p>I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do:</p> -<ul> -<li>Uninstall Windows Azure Active Directory Sync tool and reboot -<a href="https://geekyryan.com/wp-content/uploads/2015/08/2.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/2.png" alt=""></a></li> -</ul> -<p>Remove this directory and all subfolders: C:Program FilesWindows Azure Active Directory Sync -<a href="https://geekyryan.com/wp-content/uploads/2015/08/3.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/3.png" alt=""></a></p> -<p>If you created a domain account to use for DirSync, remove it. Also remove the Office 365 account you created.</p> -<ul> -<li>Delete the Group accounts that the DirSync wizard created. Their names all begin with “FIM”</li> -</ul> -<p><a href="https://geekyryan.com/wp-content/uploads/2015/08/4.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/4.png" alt=""></a></p> -<p>Uninstall MSSQL:</p> -<ul> -<li>Delete the MSSQL directory: C:Program FilesMicrosoft SQL Server</li> -<li>Reboot!</li> -<li>You should be able to install and configure DirSync now.</li> -</ul> -<p><a href="https://geekyryan.com/wp-content/uploads/2015/08/5.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/5.png" alt=""></a></p> - + http://localhost:1313/posts/2015-08-13-error-when-reinstalling-dirsync/ + Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process: I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do: - diff --git a/public/tags/azure/page/1/index.html b/public/tags/azure/page/1/index.html index c12c02f9..022be171 100644 --- a/public/tags/azure/page/1/index.html +++ b/public/tags/azure/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/azure/ - + http://localhost:1313/tags/azure/ + - + diff --git a/public/tags/azure/page/2/index.html b/public/tags/azure/page/2/index.html index abb7f61c..aa25a885 100644 --- a/public/tags/azure/page/2/index.html +++ b/public/tags/azure/page/2/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Azure · GeekyRyan + - - -azure - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + - - - - - - - - - - - - + + + + - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,667 +79,217 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - - -
    -
    - -

    Tag: azure

    - - - -
    -
    -
    -

    Azure Policy &#8211; Allowed Locations for Resource Deployment

    -
    - -
    - - -
    - Azure Policy allows us to control what actions users can perform regarding creating and managing resources in Azure. We can define policies for naming standards, require that certain extensions be installed on virtual machines, audit various resources for certain configurations… the possibilities are endless. -In this article, well focus on defining what locations users can deploy resources in. To get started, login to the Azure Portal and search for “Policy”. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Replicate an Azure VM Image Between Regions

    -
    - -
    - - -
    - Let’s say you have a VM in Azure North Central. You created this VM from a custom image that you maintain in an Azure image repository. Now, what if you wanted to create that same VM in Azure South Central, and use the same reference image? A standard image repository is limited to the region that it exists in. The answer here is to create a Shared Image Library, add the image to it, and then configure the image to replicate to other Azure regions. -
    - - -
    - Read more -
    - - - - - - - -
    - -
    -
    -
    -

    Azure Site Recovery &#8211; VMware-to-Azure: Wrong IP address discovered for VM

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Tag: Azure +

    +
    + + + -
    - - - - - - -
    -
    - -
    - -
    -
    -
    -

    Azure AD Connect No-Start-Connection

    -
    - -
    - -
    - This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working. -After forcing the sync, I opened miisclient and noticed some strange errors. -
    - - -
    - Read more -
    - - - - - - - -
    + + + -
    -
    -
    -

    Azure AD Connect Health: Latest Data is not Available in Azure Portal

    -
    - -
    - -
    - I recently had to create a new Azure AD Connect server, and found that it was not able to report health status in the Azure Portal. After some troubleshooting/research, I was able to get the health status report working by registering the health agent on the server with Azure AD Health Services. Doing this involves running one PowerShell cmdlet on your AD Connect server and providing global administrator credentials. -First, let’s test the status of the agent communication: -
    + -
    - Read more -
    + +
  • 1
  • + + - + - - - -
    - -
    -
    -
    -

    Removing a Forest from Azure AD Connect

    -
    -
    +
    +
    + © -
    - In an organization with multiple Active Directory forests, you may want to sync objects from trusted forests. Adding trusted forests to Azure AD Sync is a simple process that I will likely cover in a future article. The focus of this post is the not-so-obvious process of removing a forest from Azure AD Connect. This can be a daunting and somewhat scary thing to do. Not fully understanding the process or having someone to guide you can leave you with thoughts like “what happens when I remove the forest from Azure AD Sync? -
    - - -
    - Read more -
    - - - - + 2012 - - - -
    +
    - https://rnemeth90.github.io/posts/2018-07-13-removing-forest-from-azure-ad-connect/ - Ryan - - -
    - - - - - - -
    -
    + - - -
    -
    -
    -

    Error When Reinstalling DirSync

    -
    - -
    + - -
    - Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process: -I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do: -
    - - -
    - Read more -
    - - - + + + + - + + - -
    - - - - - + + + + - - -
    - - + - + -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/backup/index.html b/public/tags/backup/index.html index b3382403..fe5fceac 100644 --- a/public/tags/backup/index.html +++ b/public/tags/backup/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Backup · GeekyRyan + - - -backup - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,285 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Tag: backup

    - - - -
    -
    -
    -

    Backup Synology NAS to Azure Storage

    -
    -
    +
    +
    + © -
    - I’m not really a fan of photography. I don’t particularly enjoy the intracies of tuning a high-end DSLR camera. Nor am I a fan of being out in nature to photograph a fall sunrise (though, that does sound peaceful). However, I do take a lot of pictures with my phone (currently, a Pixel 6). Moreso now that I am a new father. I am protective of these photos. So much that I sync them automatically from my phone to two cloud storage providers. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-12-25-synology-backup-to-cloud/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/backup/index.xml b/public/tags/backup/index.xml index bc12f4c5..304b3a23 100644 --- a/public/tags/backup/index.xml +++ b/public/tags/backup/index.xml @@ -1,49 +1,19 @@ - backup on GeekyRyan - https://rnemeth90.github.io/tags/backup/ - GeekyRyan (backup) - Hugo -- gohugo.io - en-us + Backup on GeekyRyan + http://localhost:1313/tags/backup/ + Recent content in Backup on GeekyRyan + Hugo + en Tue, 27 Dec 2022 00:00:00 +0000 - - - - + Backup Synology NAS to Azure Storage - https://rnemeth90.github.io/posts/2022-12-25-synology-backup-to-cloud/ + http://localhost:1313/posts/2022-12-25-synology-backup-to-cloud/ Tue, 27 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-25-synology-backup-to-cloud/ - <p>I&rsquo;m not really a fan of photography. I don&rsquo;t particularly enjoy the intracies of tuning a high-end DSLR camera. Nor am I a fan of being out in nature to photograph a fall sunrise (though, that does sound peaceful). However, I do take a lot of pictures with my phone (currently, a Pixel 6). Moreso now that I am a new father. I am protective of these photos. So much that I sync them automatically from my phone to two cloud storage providers. I thought the other day, how painful it would be for either of these cloud storage providers to go offline. Though unlikely, anything is possible, right?</p> -<p>So, like any good engineer, I started looking for a solution for this concern. I have 2 Synology NAS devices here at my home. Calling a Synology a NAS is almost an insult. They are much more than that. Though they specialize in storage, they provide a plethora of apps that extend the functionality of the device. A Synology device can provide storage, email, DNS, media, etc. services though OEM and third-party apps. A single device can also link up with other devices to form a highly-available mesh of Synology services. Pretty neat for just a little black desktop box! Anyway, I&rsquo;m not a Synology salesman, so let&rsquo;s get back on track&hellip;</p> -<p>I wanted to be able to have a local copy of all of my photos (and other files) that are currently synced to the cloud. I then wanted to backup this local copy to another remote location (something like a 3-2-1 backup architecture, but not really&hellip;). Synology provides an app called Cloud Sync that can be used to sync files from a cloud storage provider like Google Photos/Drive or Microsoft OneDrive to a local device. They also provide another app called Hyper Backup that can be used to backup local files to remote storage, like an Azure Storage Account or Amazon S3 Bucket. By now, you probably get where this is going.</p> -<p>I&rsquo;m going to configure Cloud Sync to pull files down to my Synology and then use Hyper Backup to push a weekly backup to Azure Blob Storage. Let&rsquo;s dive in! -If you&rsquo;re following along, you&rsquo;ll need to install both of these apps. They are available via One-Click install in the Synology Package Center, so I won&rsquo;t cover the installation process. The setup is extremely simple as well, but I&rsquo;ll go over it just because.</p> -<p>We&rsquo;ll first setup Cloud Sync. Open Cloud Sync and click the &lsquo;+&rsquo; symbol to add a new account.</p> -<p>For my purposes, I&rsquo;m going to choose Microsoft OneDrive:</p> -<p><a href="https://rnemeth90.github.io/images/synology-cloud-sync-01.png"><img src="https://rnemeth90.github.io/images/synology-cloud-sync-01.png" alt=""></a></p> -<p>When prompted to authenticate, login to your OneDrive account. Then, configure the sync settings. You can create a name for the connection, add a local path in which to sync your files to, choose which remote folders/files to sync, the sync direction, a schedule, etc.</p> -<p><a href="https://rnemeth90.github.io/images/synology-cloud-sync-02.png"><img src="https://rnemeth90.github.io/images/synology-cloud-sync-02.png" alt=""></a></p> -<p>Click Next, and then finish the wizard. Simple.</p> -<p>Depending on the amount of files you have, you&rsquo;ll need to allow some time for your files to sync.</p> -<p>Now, we&rsquo;ll setup Hyper Backup to backup the files you sync&rsquo;d locally to remote storage. As stated previously, I&rsquo;ll be backing up my files to Azure Blob Storage. I have already created the Storage Account in Azure, and will not be covering that in this article.</p> -<p>Open Hyper Backup and click the &lsquo;+&rsquo; symbol in the lower left corner, and then click &lsquo;Data Backup Task&rsquo;. Then, choose &lsquo;Microsoft Azure&rsquo;:</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-01.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-01.png" alt=""></a> -<a href="https://rnemeth90.github.io/images/synology-hyper-backup-02.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-02.png" alt=""></a></p> -<p>On the next page, enter in your Storage Account info and then click Next. You can then choose which local folders on your Synology to backup:</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-03.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-03.png" alt=""></a></p> -<p>Click next and choose to backup application settings:</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-04.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-04.png" alt=""></a></p> -<p>On this page, we can configure the backup settings. Name the task, and configure your notification settings, schedule, compression, and encryption.</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-05.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-05.png" alt=""></a></p> -<p>On the last page, we configure our backup rotation settings. I am going to keep 31 days of backups, starting from the oldest backup. This means that at any given time I will have 31 days worth of backups in the storage account.</p> -<p><a href="https://rnemeth90.github.io/images/synology-hyper-backup-06.png"><img src="https://rnemeth90.github.io/images/synology-hyper-backup-06.png" alt=""></a></p> -<p>That&rsquo;s all for configuring the backups! Very simple. Depending on how much data you have and your ISP, it may take a while to backup your files. If you configured notifications, you should receive a notification once the job is complete.</p> - + http://localhost:1313/posts/2022-12-25-synology-backup-to-cloud/ + I&rsquo;m not really a fan of photography. I don&rsquo;t particularly enjoy the intracies of tuning a high-end DSLR camera. Nor am I a fan of being out in nature to photograph a fall sunrise (though, that does sound peaceful). However, I do take a lot of pictures with my phone (currently, a Pixel 6). Moreso now that I am a new father. I am protective of these photos. So much that I sync them automatically from my phone to two cloud storage providers. - diff --git a/public/tags/backup/page/1/index.html b/public/tags/backup/page/1/index.html index e44a36c6..03cd638d 100644 --- a/public/tags/backup/page/1/index.html +++ b/public/tags/backup/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/backup/ - + http://localhost:1313/tags/backup/ + - + diff --git a/public/tags/bash/index.html b/public/tags/bash/index.html index a744430c..fe1d55be 100644 --- a/public/tags/bash/index.html +++ b/public/tags/bash/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Bash · GeekyRyan + - - -bash - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,301 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Tag: bash

    - - - -
    -
    -
    -

    Remove Kubernetes Namespace Stuck in the Terminating State

    -
    -
    +
    +
    + © -
    - In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state. -A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/bash/index.xml b/public/tags/bash/index.xml index 438df1e5..5ebd0596 100644 --- a/public/tags/bash/index.xml +++ b/public/tags/bash/index.xml @@ -1,84 +1,19 @@ - bash on GeekyRyan - https://rnemeth90.github.io/tags/bash/ - GeekyRyan (bash) - Hugo -- gohugo.io - en-us + Bash on GeekyRyan + http://localhost:1313/tags/bash/ + Recent content in Bash on GeekyRyan + Hugo + en Sat, 04 Jun 2022 18:29:41 +0000 - - - - + Remove Kubernetes Namespace Stuck in the Terminating State - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ Sat, 04 Jun 2022 18:29:41 +0000 - - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ - <p>In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state.</p> -<p>A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. One day, you decide you no longer want this blog, so you plan to delete it. Rather than tediously deleting all of the various entities associated with this blog, you can delete the namespace that contains these entities. This will essentially ‘cascade delete’ the resources within the namespace as well.</p> -<p>After deleting the namespace for your blog, you notice that it still exists, but the state of it is ‘Terminating’, and it has been like this for a long time (hours or maybe even days).</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/06/image.png"></a></p> -<p>Kubernetes will occassionally fail to delete third-party resources when deleting a namespace, causing the namespace to linger. This can happen if the third-party API managing the resource is not responding to requests. To verify if any of these resources still exist, use this command:</p> -<pre tabindex="0"><code>kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get --show-kind --show-all --ignore-not-found -n &lt;terminating-namespace&gt; -</code></pre><p>If you happen to see any resources in the output, you can try force deleting them and then try to delete the namespace again.</p> -<p>In my experience, the majority of the time you will not find any resources still hanging around. Rather, the namespace will be completely empty. What is going on here?</p> -<p>Let’s take a look at the namespace:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ae81ff">$ kubectl get namespace darn-c101 -o yaml</span> -</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Namespace</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">annotations</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">kubectl.kubernetes.io/last-applied-configuration</span>: <span style="color:#ae81ff">|</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">kubernetes.io/metadata.name</span>: <span style="color:#ae81ff">darn-c101</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">finalizers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">kubernetes</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">status</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">conditions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">lastTransitionTime</span>: <span style="color:#e6db74">&#34;2022-06-01T19:05:31Z&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">message: &#39;Some content in the namespace has finalizers remaining</span>: <span style="color:#ae81ff">darn-c101.geekyryan.io/finalizer in 1 resource instances&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">reason</span>: <span style="color:#ae81ff">SomeFinalizersRemain</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">status</span>: <span style="color:#e6db74">&#34;True&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">NamespaceFinalizersRemaining</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">phase</span>: <span style="color:#ae81ff">Terminating</span> -</span></span></code></pre></div><p>Notice the inclusion of the finalizers field in the above JSON. Some namespaces have a finalizer defined under spec.</p> -<p>A finalizer is a special metadata key that tells Kubernetes to wait until a specific condition is met before it fully deletes a resource. Much like a finalizer in the .NET framework (does Java have those too? 😀 )</p> -<p>So when you run a command like <code>kubectl delete namespace &lt;namespace&gt;</code>, Kubernetes checks for a finalizer in the <code>metadata.finalizers</code> field. If the resource defined in the finalizer cannot be deleted, then the namespace is not deleted either. This puts the namespace into a perpetual terminating state and is never actually deleted.</p> -<p>When an object has been terminating for an excessive time, check its finalizers by inspecting the <code>metadata.finalizers</code> field in its YAML.</p> -<p>So we now know what the problem is. How can we solve it? Well, it’s actually quite simple. If you are using bash, use this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> -</span></span><span style="display:flex;"><span>namespaces<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>kubectl get ns --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Terminating -o jsonpath<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;{range .items[*]}{.metadata.name}{&#34;\n&#34;}{end}&#39;</span><span style="color:#66d9ef">)</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -z <span style="color:#e6db74">&#34;</span>$namespaces<span style="color:#e6db74">&#34;</span><span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">&#34;No namespaces to delete.&#34;</span> -</span></span><span style="display:flex;"><span> exit -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> namespace in $namespaces -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">do</span> -</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">&#34;[Removing Namespace]: </span>$namespace<span style="color:#e6db74">&#34;</span> -</span></span><span style="display:flex;"><span> kubectl get namespace $namespace -o json | tr -d <span style="color:#e6db74">&#34;\n&#34;</span> | sed <span style="color:#e6db74">&#34;s/\&#34;finalizers\&#34;: \[[^]]\+\]/\&#34;finalizers\&#34;: []/&#34;</span> | kubectl replace --raw /api/v1/namespaces/$namespace/finalize -f - &gt; /dev/null 2&gt;&amp;<span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">done</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span> -</span></span></code></pre></div><p><a href="https://gist.github.com/rnemeth90/e83bb4c8808f0d28412cb40edb2487d3">Delete Terminating Kubernetes Namespaces with Bash (github.com)</a></p> -<p>It will search for any namespace that is stuck in the terminating state and forcefully remove it by removing the finalizers field and then using <code> kubectl replace</code> to commit the change back to the Kube API.</p> -<p>If you prefer Powershell, you can use this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$terminatingNamespaces = kubectl get ns --field-selector=status.phase==Terminating -o jsonpath=<span style="color:#e6db74">&#34;{range .items[*]}{.metadata.name}{&#39;\n&#39;}{end}&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($ns <span style="color:#66d9ef">in</span> $terminatingNamespaces) { -</span></span><span style="display:flex;"><span> Write-Verbose <span style="color:#e6db74">&#39;[FOUND]: Forcefully removing $ns&#39;</span> -</span></span><span style="display:flex;"><span> $jsonObj = kubectl get namespace $ns -o json | ConvertFrom-Json | foreach-object { $_.spec.finalizers = @(); $_ } | -</span></span><span style="display:flex;"><span> convertto-json | kubectl replace --raw /api/v1/namespaces/$namespace/finalize <span style="color:#f92672">-f</span> - -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><a href="https://gist.github.com/rnemeth90/19d7de622a5009c1cf908c5d4deb5358">Delete Terminating Kubernetes Namespaces with Powershell (github.com)</a></p> -<p>It does the same thing as the bash script, just in more of a Window-zy way.</p> -<p>It’s that simple. I hope this was helpful. If you have any questions, comments, or concerns, please feel free to reach out.</p> - + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state. A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. - diff --git a/public/tags/bash/page/1/index.html b/public/tags/bash/page/1/index.html index 04d1685a..244bec4a 100644 --- a/public/tags/bash/page/1/index.html +++ b/public/tags/bash/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/bash/ - + http://localhost:1313/tags/bash/ + - + diff --git a/public/tags/c#/index.html b/public/tags/c#/index.html index 073bdf08..78fb0910 100644 --- a/public/tags/c#/index.html +++ b/public/tags/c#/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: C# · GeekyRyan + - - -c# - GeekyRyan - - - - - - - - - - + - - + + + - - + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,382 +79,161 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    -
    -
    - -

    Tag: c#

    - + 2022-12-28 + Handling Graceful Shutdown in a .NET App Hosted in Kubernetes + +
  • + 2022-06-12 + EF Core &#8211; Unable to create an object of type DbContext +
  • -
    -
    -
    -

    Handling Graceful Shutdown in a .NET App Hosted in Kubernetes

    -
    - -
    + + - -
    - I was recently involved with troubleshooting some API’s hosted in Kubernetes throwing http/502’s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    EF Core &#8211; Unable to create an object of type DbContext

    -
    -
    +
    +
    + © -
    - This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it! -When running EF Core migrations in a solution, you may come across this error: -There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio. -To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - +
    +
    -
    - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/c#/index.xml b/public/tags/c#/index.xml index 531448a0..4abc2340 100644 --- a/public/tags/c#/index.xml +++ b/public/tags/c#/index.xml @@ -1,155 +1,26 @@ - c# on GeekyRyan - https://rnemeth90.github.io/tags/c#/ - GeekyRyan (c#) - Hugo -- gohugo.io - en-us + C# on GeekyRyan + http://localhost:1313/tags/c%23/ + Recent content in C# on GeekyRyan + Hugo + en Wed, 28 Dec 2022 00:00:00 +0000 - - - - + Handling Graceful Shutdown in a .NET App Hosted in Kubernetes - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ Wed, 28 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ - <p>I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. It was actually a combination of these blogs (and the resolutions posted) that ended up resolving our issue.</p> -<h3 id="so-what-was-actually-causing-the-502s" >So what was actually causing the 502&rsquo;s? -<span> - <a href="#so-what-was-actually-causing-the-502s"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h3><p>As stated, these APIs are hosted in Kubernetes. They are written primarily in c# (.NET Framework) and hosted in Windows Server Core containers. The pods are load balanced using a service, and we have an Nginx ingress on top of the service. Nothing fancy, just a typical setup that you may have seen or even built yourself. We implement automatic scaling for our replica sets using a standard Kubernetes-native HPA or Keda, depending on the app. We have autoscale rules defined for the pods. Our clusters are hosted in Azure Kubernetes Service, and we autoscale our node pools. So, there are several layers of scaling happening in our clusters at any given time. Occasionally, when a pod was handling a client request, Kubelet or a controller would come along and scale the pod in. We were initially under the belief that the <code>terminationGracePeriodSeconds</code> value within our deployment would allow the pod to continue running for the defined number of seconds. However, we were mistaken. This value tells Kubernetes to allow the application running within the pod some time to clean up. It does <em>not</em> tell the app to continue running for the defined number of seconds after it receives a sigterm signal. This logic actually needs to be implemented within the application itself, or with a prestop hook. The prestop method is <a href="https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/">well documented</a>, so I will not cover it here.</p> -<p>To implement this in a .NET Framework app running in Windows, you need to add this registry key to your container.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">RUN</span> reg add hklm<span style="color:#ae81ff">\s</span>ystem<span style="color:#ae81ff">\c</span>urrentcontrolset<span style="color:#ae81ff">\c</span>ontrol /v WaitToKillServiceTimeout /t REG_SZ /d <span style="color:#ae81ff">60000</span> /f<span style="color:#960050;background-color:#1e0010"> -</span></span></span></code></pre></div><p>This value tells Windows to wait a number of milliseconds before shutting down Normally, Windows only waits for 5 seconds (default) before shutting down any &lsquo;background&rsquo; processes. Windows forcibly shuts down processes after this period of time.</p> -<p>Next, in the startup class, we&rsquo;ll add the following code. I have added inline comments to explain.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c#" data-lang="c#"><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">namespace</span> MyApp.APIConsoleHost -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Program</span> -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Register the SetConsoleCtrlHandler function in kernel32.dll in the -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> application to capture CTRL_SHUTDOWN_EVENT events for resource reclamation -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e"> [DllImport(&#34;Kernel32&#34;)]</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">extern</span> <span style="color:#66d9ef">bool</span> SetConsoleCtrlHandler(HandlerRoutine handler, <span style="color:#66d9ef">bool</span> <span style="color:#66d9ef">add</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Define a delegate for our handler routine</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">delegate</span> <span style="color:#66d9ef">bool</span> HandlerRoutine(CtrlTypes ctrlType); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">volatile</span> ManualResetEvent _exitEvent = <span style="color:#66d9ef">new</span> ManualResetEvent(<span style="color:#66d9ef">false</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> HandlerRoutine _handler; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Define the event types that we want to handle when the application receives a SIGTERM -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_C_EVENT = 0, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_BREAK_EVENT = 1, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_CLOSE_EVENT = 2, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_LOGOFF_EVENT = 5, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_SHUTDOWN_EVENT = 6 -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">enum</span> CtrlTypes -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> CTRL_SHUTDOWN_EVENT = <span style="color:#ae81ff">6</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Here we are defining how we want to handle the shutdown -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We get a timeout value from an env variable named APP_SHUTDOWN_TIMEOUT -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> If that env variable is not found, we default to 60 seconds. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We then switch on our CtrlTypes enum and handle each value accordingly, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then return true. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">bool</span> ConsoleCtrlCheck(CtrlTypes ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> timeout = ConfigurationManager.AppSettings[<span style="color:#e6db74">&#34;APP_SHUTDOWN_TIMEOUT&#34;</span>]; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> (<span style="color:#66d9ef">string</span>.IsNullOrEmpty(timeout)) { timeout = <span style="color:#e6db74">&#34;60&#34;</span>; } -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">int</span> counter = <span style="color:#66d9ef">int</span>.Parse(timeout); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">switch</span> (ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> CtrlTypes.CTRL_SHUTDOWN_EVENT: -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] CTRL_SHUTDOWN received&#34;</span>); -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] Web Server is stopping in {counter} seconds&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">while</span> (counter &gt; <span style="color:#ae81ff">0</span>) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> Thread.Sleep(TimeSpan.FromSeconds(<span style="color:#ae81ff">1</span>)); -</span></span><span style="display:flex;"><span> counter--; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.Set(); -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span>; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span>: -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">false</span>; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Our main method is pretty standard. However, we first register a new handler (_handler), -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then pass it to to the SetConsoleCtrlHandler() method we imported from Kernel32.dll. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> The only other &#39;unique&#39; thing is the _exitEvent.WaitOne(); call defined at the bottom of main(). -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> This is necessary so that main does not immediately exit, and wait&#39;s for a signal. We defined a -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> property for this _exitEvent of type ManualResetEvent at the top of this class file. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> Main(<span style="color:#66d9ef">string</span>[] args) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> _handler += <span style="color:#66d9ef">new</span> HandlerRoutine(ConsoleCtrlCheck); -</span></span><span style="display:flex;"><span> SetConsoleCtrlHandler(_handler, <span style="color:#66d9ef">true</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = BuildStartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> WebApp.Start&lt;SelfHostStartup&gt;(startOptions); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">&#34;Press CTRL+C to stop it&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.WaitOne(); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> StartOptions BuildStartOptions() -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = <span style="color:#66d9ef">new</span> StartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted start options</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> startOptions; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>To prevent the HandlerRoutine instance from being recycled by the GC before the program exits, the HandlerRoutine must be static (as seen in the above example). This is important because if the handlerroutine is recycled before the application is finished, it will throw an error, as shown here:</p> -<pre tabindex="0"><code>A callback was made on a garbage collected delegate of type &#39;Program+HandlerRoutine::Invoke&#39;. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called. -</code></pre> + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. - EF Core &#8211; Unable to create an object of type DbContext - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ Sun, 12 Jun 2022 13:58:52 +0000 - - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ - <p>This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it!</p> -<p>When running EF Core migrations in a solution, you may come across this error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-1-1024x142.png"></a></p> -<p>There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio.</p> -<p>To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-2.png"></a></p> -<p>If you are using clean architecture, or some other architecture that has your startup context and your dbContext in different projects, you will need to set your startup project to your runtime, and the ‘Default Project’ in the package manager console to the project containing your dbContext.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-3-1024x493.png"></a></p> - + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it! When running EF Core migrations in a solution, you may come across this error: There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio. To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’. - diff --git a/public/tags/c#/page/1/index.html b/public/tags/c#/page/1/index.html index 3922843c..6d712977 100644 --- a/public/tags/c#/page/1/index.html +++ b/public/tags/c#/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/c#/ - + http://localhost:1313/tags/c%23/ + - + diff --git a/public/tags/certification/index.html b/public/tags/certification/index.html index 759a6adb..2c4d2f21 100644 --- a/public/tags/certification/index.html +++ b/public/tags/certification/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Certification · GeekyRyan + - - -certification - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,285 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Tag: certification

    - - - -
    -
    -
    -

    Exam AZ-303: Microsoft Azure Architect Technologies Study Guide

    -
    -
    +
    +
    + © -
    - I recently passed the AZ-303 exam. Below are some of the resources I used to prepare for the exam. In addition to the links below, I also used Alan Rodrigues’ course on Udemy. https://www.udemy.com/course/az-102-azure-administrator-certification-transition/ The Udemy course and Microsoft Docs are enough to pass the exam. The course has some good practice exams and labs that align well with what you’ll see on the real exam regarding difficulty. I was scoring in the high 90’s on the Udemy exams. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/certification/index.xml b/public/tags/certification/index.xml index c8ea3eaa..3999ceed 100644 --- a/public/tags/certification/index.xml +++ b/public/tags/certification/index.xml @@ -1,702 +1,19 @@ - certification on GeekyRyan - https://rnemeth90.github.io/tags/certification/ - GeekyRyan (certification) - Hugo -- gohugo.io - en-us + Certification on GeekyRyan + http://localhost:1313/tags/certification/ + Recent content in Certification on GeekyRyan + Hugo + en Wed, 16 Dec 2020 14:44:00 +0000 - - - - + Exam AZ-303: Microsoft Azure Architect Technologies Study Guide - https://rnemeth90.github.io/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ + http://localhost:1313/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ Wed, 16 Dec 2020 14:44:00 +0000 - - https://rnemeth90.github.io/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ - <p><span style="font-family: arial;">I recently passed the AZ-303 exam. Below are some of the resources I used to prepare for the exam. In addition to the links below, I also used Alan Rodrigues’ course on Udemy. </span></p> -<p><span style="font-family: arial;"><a href="https://www.udemy.com/course/az-102-azure-administrator-certification-transition/">https://www.udemy.com/course/az-102-azure-administrator-certification-transition/</a> -</span></p> -<p><span style="font-family: arial;">The Udemy course and Microsoft Docs are enough to pass the exam. The course has some good practice exams and labs that align well with what you’ll see on the real exam regarding difficulty. I was scoring in the high 90’s on the Udemy exams. On the real exam, my score was 923. So, I think, if you comprehend the material well, and get high scores on Udemy practice exams, you’ll do well on the real exam.</span></p> -<p><span style="font-family: arial;">Just wanted to share my experience, hopefully it helps.</span></p> -<p><strong><u><span style="font-size: large;">Implement and Monitor an Azure Infrastructure (50-55%)</span></u></strong></p> -<p><span style="font-size: medium;"><strong>Implement cloud infrastructure monitoring</strong></span></p> -<ul> -<li> -<p>monitor security</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/security-center/security-center-introduction">What is Azure Security Center?</a></p> -</li> -<li> -<p>monitor performance</p> -</li> -<li> -<p>configure diagnostic settings on resources</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/diagnostic-settings">Create diagnostic settings to send platform logs and metrics to different destinations</a></p> -</li> -<li> -<p>create a performance baseline for resources</p> -</li> -<li> -<p><a href="https://cloudacademy.com/course/analyzing-resource-utilization-azure/resource-baseline/">Analyzing Resource Utilization on Azure</a></p> -</li> -<li> -<p>monitor for unused resources</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cost-management-billing/costs/quick-acm-cost-analysis?tabs=azure-portal">Quickstart: Explore and analyze costs with cost analysis</a></p> -</li> -<li> -<p>monitor performance capacity</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/insights/vminsights-performance">How to chart performance with Azure Monitor for VMs</a></p> -</li> -<li> -<p>visualize diagnostics data using Azure Monitor</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/workbooks-overview">Azure Monitor Workbooks</a></p> -</li> -<li> -<p>monitor health and availability</p> -</li> -<li> -<p>monitor networking</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/insights/network-insights-overview">Azure Monitor for Networks</a></p> -</li> -<li> -<p>monitor service health</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/service-health/service-health-overview">Service Health overview</a></p> -</li> -<li> -<p>monitor cost</p> -</li> -<li> -<p>monitor spend</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cost-management-billing/costs/quick-acm-cost-analysis?tabs=azure-portal">Quickstart: Explore and analyze costs with cost analysis</a></p> -</li> -<li> -<p>report on spend</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cost-management-billing/understand/download-azure-invoice">View and download your Microsoft Azure invoice</a></p> -</li> -<li> -<p>configure advanced logging</p> -</li> -<li> -<p>implement and configure Azure Monitor insights, including App Insights, Networks, Containers</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/monitor-reference">What is monitored by Azure Monitor?</a></p> -</li> -<li> -<p>configure a Log Analytics workspace</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/learn/quick-create-workspace">Create a Log Analytics workspace in the Azure portal</a></p> -</li> -<li> -<p>configure logging for workloads</p> -</li> -<li> -<p>initiate automated responses by using Action Groups</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/action-groups">Create and manage action groups in the Azure portal</a></p> -</li> -<li> -<p>configure and manage advanced alerts</p> -</li> -<li> -<p>collect alerts and metrics across multiple subscriptions</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/alerts-metric">Create, view, and manage metric alerts using Azure Monitor</a></p> -</li> -<li> -<p>view Alerts in Azure Monitor logs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-monitor/platform/alerts-activity-log">Create, view, and manage activity log alerts by using Azure Monitor</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement storage accounts</span></strong></p> -<ul> -<li> -<p>select storage account options based on a use case</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-account-create?tabs=azure-portal">Create a storage account</a></p> -</li> -<li> -<p>configure Azure Files and blob storage</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/files/storage-how-to-create-file-share?tabs=azure-portal">Create an Azure file share</a></p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-portal">Quickstart: Upload, download, and list blobs with the Azure portal</a></p> -</li> -<li> -<p>configure network access to the storage account</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-network-security">Configure Azure Storage firewalls and virtual networks</a></p> -</li> -<li> -<p>implement Shared Access Signatures and access policies</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-sas-overview">Grant limited access to Azure Storage resources using shared access signatures (SAS)</a></p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/rest/api/storageservices/define-stored-access-policy">Define a stored access policy</a></p> -</li> -<li> -<p>implement Azure AD authentication for storage</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-auth-aad">Authorize access to blobs and queues using Azure Active Directory</a></p> -</li> -<li> -<p>manage access keys</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-account-keys-manage?tabs=azure-portal">Manage storage account access keys</a></p> -</li> -<li> -<p>implement Azure storage replication</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/blobs/object-replication-configure?tabs=portal">Configure object replication for block blobs</a></p> -</li> -<li> -<p>implement Azure storage account failover</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-disaster-recovery-guidance">Disaster recovery and storage account failover</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement VMs for Windows and Linux</span></strong></p> -<ul> -<li> -<p>configure High Availability</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/manage-availability">Manage the availability of Linux virtual machines</a></p> -</li> -<li> -<p>configure storage for VMs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/managed-disks-overview">Introduction to Azure managed disks</a></p> -</li> -<li> -<p>select virtual machine size</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/sizes">Sizes for virtual machines in Azure</a></p> -</li> -<li> -<p>implement Azure Dedicated Hosts</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/dedicated-hosts-portal">Deploy VMs and scale sets to dedicated hosts using the portal</a></p> -</li> -<li> -<p>deploy and configure scale sets</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machine-scale-sets/quick-create-portal">Quickstart: Create a virtual machine scale set in the Azure portal</a></p> -</li> -<li> -<p>configure Azure Disk Encryption</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/windows/disk-encryption-overview">Azure Disk Encryption for Windows VMs</a></p> -</li> -</ul> -<p><span style="font-size: medium;"><strong>Automate deployment and configuration of resources</strong></span></p> -<ul> -<li> -<p>save a deployment as an Azure Resource Manager template</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/export-template-portal">Single and multi-resource export to a template in Azure portal</a></p> -</li> -<li> -<p>modify Azure Resource Manager template</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/overview">What are ARM templates?</a></p> -</li> -<li> -<p>evaluate location of new resources</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/view-activity-logs">View activity logs to monitor actions on resources</a></p> -</li> -<li> -<p>configure a virtual disk template</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/windows/capture-image-resource">Create a managed image of a generalized VM in Azure</a></p> -</li> -<li> -<p>deploy from a template</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/deploy-vms-from-vhd-templates/">Deploy Azure virtual machines from VHD templates</a></p> -</li> -<li> -<p>manage a template library</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-machines/shared-image-galleries">Shared Image Galleries overview</a></p> -</li> -<li> -<p>create and execute an automation runbook</p> -</li> -<li> -<p><a href="https://azure.microsoft.com/en-us/blog/azure-automation-runbook-management/">Getting Started With Azure Automation – Runbook Management</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement virtual networking</span></strong></p> -<ul> -<li> -<p>implement VNet to VNet connections</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/vpn-gateway/vpn-gateway-howto-vnet-vnet-resource-manager-portal">Configure a VNet-to-VNet VPN gateway connection by using the Azure portal</a></p> -</li> -<li> -<p>implement VNet peering</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-peering-overview">Virtual network peering</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement Azure Active Directory</span></strong></p> -<ul> -<li> -<p>add custom domains</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/add-custom-domain">Add your custom domain name using the Azure Active Directory portal</a></p> -</li> -<li> -<p>configure Azure AD Identity Protection</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/identity-protection/overview-identity-protection">What is Identity Protection?</a></p> -</li> -<li> -<p>implement self-service password reset</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/tutorial-enable-sspr">Tutorial: Enable users to unlock their account or reset passwords using Azure Active Directory self-service password reset</a></p> -</li> -<li> -<p>implement Conditional Access including MFA</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/conditional-access/howto-conditional-access-policy-all-users-mfa">Conditional Access: Require MFA for all users</a></p> -</li> -<li> -<p>configure user accounts for MFA</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-userstates">Enable per-user Azure AD Multi-Factor Authentication to secure sign-in events</a></p> -</li> -<li> -<p>configure fraud alerts</p> -</li> -<li> -<p><a href="Enable%20per-user%20Azure%20AD%20Multi-Factor%20Authentication%20to%20secure%20sign-in%20events">Fraud alert</a></p> -</li> -<li> -<p>configure bypass options</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-server-settings#one-time-bypass">One-time bypass</a></p> -</li> -<li> -<p>configure Trusted IPs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-mfasettings#trusted-ips">Trusted IPs</a></p> -</li> -<li> -<p>configure verification methods</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/concept-sspr-howitworks#authentication-methods">Authentication methods</a></p> -</li> -<li> -<p>implement and manage guest accounts</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/external-identities/b2b-quickstart-add-guest-users-portal">Quickstart: Add guest users to your directory in the Azure portal</a></p> -</li> -<li> -<p>manage multiple directories</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/enterprise-users/licensing-directory-independence">Understand how multiple Azure Active Directory organizations interact</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement and manage hybrid identities</span></strong></p> -<ul> -<li> -<p>install and configure Azure AD Connect</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-install-express">Getting started with Azure AD Connect using express settings</a></p> -</li> -<li> -<p>identity synchronization options</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/plan-connect-user-signin">Azure AD Connect user sign-in options</a></p> -</li> -<li> -<p>configure and manage password sync and password writeback</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/tutorial-enable-sspr-writeback">Tutorial: Enable Azure Active Directory self-service password reset writeback to an on-premises environment</a></p> -</li> -<li> -<p>configure single sign-on</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-sso-quick-start">Azure Active Directory Seamless Single Sign-On: Quickstart</a></p> -</li> -<li> -<p>use Azure AD Connect Health</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/whatis-azure-ad-connect#what-is-azure-ad-connect-health">What is Azure AD Connect Health?</a></p> -</li> -</ul> -<p><strong><u><span style="font-size: large;">Implement Management and Security Solutions (25-30%)</span></u></strong></p> -<p><span style="font-size: medium;"><strong>Manage workloads in Azure</strong></span></p> -<ul> -<li> -<p>migrate workloads using Azure Migrate</p> -</li> -<li> -<p>assess infrastructure</p> -</li> -<li> -<p>select a migration method</p> -</li> -<li> -<p>prepare the on-premises for migration</p> -</li> -<li> -<p>recommend target infrastructure</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/migrate/tutorial-migrate-hyper-v">Migrate Hyper-V VMs to Azure</a></p> -</li> -<li> -<p>implement Azure Backup for VMs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/backup/backup-azure-vms-first-look-arm">Back up an Azure VM from the VM settings</a></p> -</li> -<li> -<p>implement disaster recovery</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/site-recovery/azure-to-azure-tutorial-enable-replication">Tutorial: Set up disaster recovery for Azure VMs</a></p> -</li> -<li> -<p>implement Azure Update Management</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/automation/update-management/enable-from-vm">Enable Update Management for an Azure VM</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement load balancing and network security</span></strong></p> -<ul> -<li> -<p>implement Azure Load Balancer</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/load-balancer/load-balancer-overview">What is Azure Load Balancer?</a></p> -</li> -<li> -<p>implement an application gateway</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/application-gateway/overview">What is Azure Application Gateway?</a></p> -</li> -<li> -<p>implement a Web Application Firewall</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/web-application-firewall/overview">What is Azure Web Application Firewall?</a></p> -</li> -<li> -<p>implement Azure Firewall</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/firewall/overview">What is Azure Firewall?</a></p> -</li> -<li> -<p>implement the Azure Front Door Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/frontdoor/quickstart-create-front-door">Quickstart: Create a Front Door for a highly available global web application</a></p> -</li> -<li> -<p>implement Azure Traffic Manager</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/traffic-manager/traffic-manager-overview">What is Traffic Manager?</a></p> -</li> -<li> -<p>implement Network Security Groups and Application Security Groups</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-network/network-security-groups-overview">Network security groups</a></p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/virtual-network/application-security-groups">Application security groups</a></p> -</li> -<li> -<p>implement Bastion</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/bastion/">Azure Bastion documentation</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement and manage Azure governance solutions</span></strong></p> -<ul> -<li> -<p>create and manage hierarchical structure that contains management groups</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/governance/management-groups/overview">What are Azure management groups?</a></p> -</li> -<li> -<p>subscriptions and resource groups</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-setup-guide/organize-resources?tabs=AzureManagementGroupsAndHierarchy">Organize your Azure resources effectively</a></p> -</li> -<li> -<p>assign RBAC roles</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal">Add or remove Azure role assignments using the Azure portal</a></p> -</li> -<li> -<p>create a custom RBAC role</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/custom-roles">Azure custom roles</a></p> -</li> -<li> -<p>configure access to Azure resources by assigning roles</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal">Add or remove Azure role assignments using the Azure portal</a></p> -</li> -<li> -<p>configure management access to Azure</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/manage-subscription-access-azure-rbac/">Manage access to an Azure subscription by using Azure role-based access control (RBAC)</a></p> -</li> -<li> -<p>interpret effective permissions</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/check-access">Quickstart: Check access for a user to Azure resources</a></p> -</li> -<li> -<p>set up and perform an access review</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/governance/access-reviews-overview">What are Azure AD access reviews?</a></p> -</li> -<li> -<p>implement and configure an Azure Policy</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/governance/policy/assign-policy-portal">Quickstart: Create a policy assignment to identify non-compliant resources</a></p> -</li> -<li> -<p>implement and configure an Azure Blueprint</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/governance/blueprints/overview">What is Azure Blueprints?</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Manage security for applications</span></strong></p> -<ul> -<li> -<p>implement and configure KeyVault</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/configure-and-manage-azure-key-vault/">Configure and manage secrets in Azure Key Vault</a></p> -</li> -<li> -<p>implement and configure Managed Identities</p> -</li> -<li> -<p><a href="https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=18fbca16-2224-45f6-85b0-f7bf2b39b3f3&amp;nonce=ef221978-b465-49a1-9226-e8a0e4d25480&amp;prompt=none&amp;redirect_uri=https%3A%2F%2Fdocs.microsoft.com%2F_themes%2Fdocs.theme%2Fmaster%2Fen-us%2F_themes%2Fglobal%2Fsign-in.html&amp;response_mode=fragment&amp;response_type=id_token&amp;scope=openid%20profile&amp;sso_reload=true&amp;state=silent%3A%2F%2Fhttps%3A%2F%2Fdocs.microsoft.com&amp;fromOrigin=https%3A%2F%2Fdocs.microsoft.com&amp;iframe-request-id=685d3411-99a9-4f94-81e4-d9b8af575600">What are managed identities for Azure resources?</a></p> -</li> -<li> -<p>register and manage applications in Azure AD</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app">Quickstart: Register an application with the Microsoft identity platform</a></p> -</li> -</ul> -<p><strong><u><span style="font-size: large;">Implement Solutions for Apps (10-15%)</span></u></strong></p> -<p><strong><span style="font-size: medium;">Implement an application infrastructure</span></strong></p> -<ul> -<li> -<p>create and configure Azure App Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/quickstart-dotnetcore?tabs=netcore31&amp;pivots=platform-linux">Quickstart: Create an ASP.NET Core web app in Azure</a></p> -</li> -<li> -<p>create an App Service Web App for Containers</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/deploy-run-container-app-service/">Deploy and run a containerized web app with Azure App Service</a></p> -</li> -<li> -<p>create and configure an App Service plan</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/app-service-plan-manage">Manage an App Service plan in Azure</a></p> -</li> -<li> -<p>configure an App Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/configure-common">Configure an App Service app in the Azure portal</a></p> -</li> -<li> -<p>configure networking for an App Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/web-sites-integrate-with-vnet">Integrate your app with an Azure virtual network</a></p> -</li> -<li> -<p>create and manage deployment slots</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/app-service/deploy-staging-slots">Set up staging environments in Azure App Service</a></p> -</li> -<li> -<p>implement Logic Apps</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/logic-apps/quickstart-create-first-logic-app-workflow">Quickstart: Create your first Logic Apps workflow – Azure portal</a></p> -</li> -<li> -<p>implement Azure Functions</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-azure-function">Create your first function in the Azure portal</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement container-based applications </span></strong></p> -<ul> -<li> -<p>create a container image</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/container-registry/container-registry-quickstart-task-cli">Quickstart: Build and run a container image using Azure Container Registry Tasks</a></p> -</li> -<li> -<p>configure Azure Kubernetes Service</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/aks/kubernetes-walkthrough-portal">Quickstart: Deploy an Azure Kubernetes Service (AKS) cluster using the Azure portal</a></p> -</li> -<li> -<p>publish and automate image deployment to the Azure Container Registry</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/container-instances/container-instances-using-azure-container-registry">Deploy to Azure Container Instances from Azure Container Registry</a></p> -</li> -<li> -<p>publish a solution on an Azure Container Instance</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/container-instances/container-instances-quickstart-portal">Quickstart: Deploy a container instance in Azure using the Azure portal</a></p> -</li> -</ul> -<p><strong><u>Implement and Manage Data Platforms (10-15%)</u></strong></p> -<p><strong><span style="font-size: medium;">Implement NoSQL databases</span></strong></p> -<ul> -<li> -<p>configure storage account tables</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/storage/tables/table-storage-quickstart-portal">Quickstart: Create an Azure Storage table in the Azure portal</a></p> -</li> -<li> -<p>select appropriate CosmosDB APIs</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/learn/modules/choose-api-for-cosmos-db/">Choose the appropriate API for Azure Cosmos DB</a></p> -</li> -<li> -<p>set up replicas in CosmosDB</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/cosmos-db/distribute-data-globally">Distribute your data globally with Azure Cosmos DB</a></p> -</li> -</ul> -<p><strong><span style="font-size: medium;">Implement Azure SQL databases</span></strong></p> -<ul> -<li> -<p>configure Azure SQL database settings</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-sql/database/single-database-create-quickstart?tabs=azure-portal">Quickstart: Create an Azure SQL Database single database</a></p> -</li> -<li> -<p>implement Azure SQL Database managed instances</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-sql/managed-instance/sql-managed-instance-paas-overview">What is Azure SQL Managed Instance?</a></p> -</li> -<li> -<p>configure HA for an Azure SQL database</p> -</li> -<li> -<p><a href="https://docs.microsoft.com/en-us/azure/azure-sql/database/high-availability-sla">High availability for Azure SQL Database and SQL Managed Instance</a></p> -</li> -<li> -<p>publish an Azure SQL database</p> -</li> -</ul> - + http://localhost:1313/posts/2020-12-16-exam-az-303-microsoft-azure-architect/ + I recently passed the AZ-303 exam. Below are some of the resources I used to prepare for the exam. In addition to the links below, I also used Alan Rodrigues’ course on Udemy. https://www.udemy.com/course/az-102-azure-administrator-certification-transition/ The Udemy course and Microsoft Docs are enough to pass the exam. The course has some good practice exams and labs that align well with what you’ll see on the real exam regarding difficulty. I was scoring in the high 90’s on the Udemy exams. - diff --git a/public/tags/certification/page/1/index.html b/public/tags/certification/page/1/index.html index 14fe90a5..cb7c1957 100644 --- a/public/tags/certification/page/1/index.html +++ b/public/tags/certification/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/certification/ - + http://localhost:1313/tags/certification/ + - + diff --git a/public/tags/ci/cd/index.html b/public/tags/ci/cd/index.html index 58b23ee0..424d7933 100644 --- a/public/tags/ci/cd/index.html +++ b/public/tags/ci/cd/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: CI/CD · GeekyRyan + - - -CI/CD - GeekyRyan - - - - - - - - - - + - - + + + - - + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,363 +79,161 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    -
    -
    - -

    Tag: CI/CD

    - + 2022-12-23 + Building a Golang App with Github Actions + +
  • + 2022-01-14 + Continuous Deployment Models +
  • -
    -
    -
    -

    Building a Golang App with Github Actions

    -
    - -
    + + - -
    - In this article, we’ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app written in any language though. We’ll cover the following: -What are github actions? Setting up the workflow to build, test, and deploy a binary Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Continuous Deployment Models

    -
    -
    +
    +
    + © -
    - When deploying new software releases to servers or (insert -as-a-service> here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments. -Blue/Green Deployments Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. Instead, it gets deployed to another set of servers (blue) first. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - +
    +
    -
    - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/ci/cd/index.xml b/public/tags/ci/cd/index.xml index 18593d1d..c73dfde6 100644 --- a/public/tags/ci/cd/index.xml +++ b/public/tags/ci/cd/index.xml @@ -2,166 +2,25 @@ CI/CD on GeekyRyan - https://rnemeth90.github.io/tags/ci/cd/ - GeekyRyan (CI/CD) - Hugo -- gohugo.io - en-us - - - - + http://localhost:1313/tags/ci/cd/ + Recent content in CI/CD on GeekyRyan + Hugo + en + Fri, 23 Dec 2022 00:00:00 +0000 + Building a Golang App with Github Actions - https://rnemeth90.github.io/posts/2022-12-24-gh-actions-copy/ + http://localhost:1313/posts/2022-12-24-gh-actions-copy/ Fri, 23 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-24-gh-actions-copy/ - <p>In this article, we&rsquo;ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app -written in any language though. We&rsquo;ll cover the following:</p> -<ol> -<li>What are github actions?</li> -<li>Setting up the workflow to build, test, and deploy a binary</li> -</ol> -<p>Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. They are powerful and I suggest you read more at the <a href="https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions">Official Docs</a></p> -<p>To get started, we&rsquo;ll need a golang app to build. You can use my example <a href="https://github.com/rnemeth90/golang-github-action-example">here</a> if you do not have your own.</p> -<p>The process is relatively simple. At the root of your repo, create the following directories:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>mkdir -p .github/workflows -</span></span></code></pre></div><p>Then create a yaml file (you can name it anything you want) with the content below:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">name</span>: <span style="color:#ae81ff">build-release-binary</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">run-name</span>: <span style="color:#ae81ff">Create Github Release for GoLang binary</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># anytime we push to our repo with a tag starting with the</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># letter &#39;r&#39;, we run the build</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">on</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">push</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tags</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#e6db74">&#39;r*&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">jobs</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">build</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">runs-on</span>: <span style="color:#ae81ff">ubuntu-22.04</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">permissions</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">contents</span>: <span style="color:#ae81ff">write</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># checkout our github repo to the build agent</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/checkout@v3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">fetch-depth</span>: <span style="color:#ae81ff">0</span> <span style="color:#75715e"># get all tags, needed to get git log</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">ref</span>: <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Setup the Go environment</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">setup Go Lang</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">id</span>: <span style="color:#ae81ff">build</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/setup-go@v3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">go-version</span>: <span style="color:#e6db74">&#39;^1.19.2&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Build our application</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go version -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> cd src -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [ ! -e *.mod ]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go mod init ${GITHUB_REPOSITORY} -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go mod tidy -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go build -ldflags &#34;-X main.Version=${GITHUB_REF_NAME} -X main.BuiltBy=github-actions&#34; main.go -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> execFile=$(find . -type f -executable)</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Output more values for debugging</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git version</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git branch</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git tag</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># tag our release</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">get semantic tag version and release notes from commit messages</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">id</span>: <span style="color:#ae81ff">tag</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">run</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> currentTag=${GITHUB_REF_NAME} -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> major_minor=$(echo &#34;$currentTag&#34; | cut -d&#39;.&#39; -f1-2) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> patch=$(echo &#34;$currentTag&#34; | cut -d&#39;.&#39; -f3) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> # avoid empty patch number -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> [ -n &#34;$patch&#34; ] &amp;&amp; ((patch--)) || patch=&#34;.x&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> previousTag=&#34;${major_minor}.${patch}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;&#34; &gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if git tag | grep $previousTag ; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git log -q ${currentTag}...${previousTag} --pretty=&#34;- %s&#34; -q --no-color &gt;&gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> else -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git log --pretty=&#34;- %s&#34; -q --no-color &gt;&gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> line_count=$(cat body.log | wc -l) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;currentTag=$currentTag&#34; &gt;&gt; $GITHUB_OUTPUT -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;previousTag=$previousTag&#34; &gt;&gt; $GITHUB_OUTPUT -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;line_count=$line_count&#34; &gt;&gt; $GITHUB_OUTPUT</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># create Github release with release note from file and binary asset attached</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">ncipollo/release-action@v1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">${{ env.GITHUB_REF_NAME }}</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tag</span>: <span style="color:#ae81ff">${{ env.GITHUB_REF_NAME }}</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">artifacts</span>: <span style="color:#e6db74">&#34;src/main&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">bodyFile</span>: <span style="color:#e6db74">&#34;body.log&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">token</span>: <span style="color:#ae81ff">${{ secrets.GITHUB_TOKEN }}</span> -</span></span></code></pre></div><p>Each step within this workflow starts with a hyphen. The steps are well-commented, so I will not explain them further. Once you have this file in your repo, push it to github. Then navigate to the Actions tab in your repository and you should see your workflow on the left hand side of the screen.</p> -<p><a href="https://rnemeth90.github.io/images/gh-actions-1.png"><img src="https://rnemeth90.github.io/images/gh-actions-1.png" alt=""></a></p> -<p>Now that we have our workflow setup, to get it run, all you need to do is tag and push your release to github. To do that, you can run the script in my repo <a href="https://github.com/rnemeth90/golang-github-action-example/blob/main/create_new_gh_release.sh">create_new_gh_release.sh</a> or simply run the following commands (be sure to change the tag as needed):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>newtag<span style="color:#f92672">=</span>r1.0.0 -</span></span><span style="display:flex;"><span>git tag $newtag <span style="color:#f92672">&amp;&amp;</span> git push origin $newtag -</span></span></code></pre></div><p>Now, go back to the Actions tab in your repo, and you should see the build running. Once it completes, go back to the Code tab in your github repo and you will see the release on the right hand side of the screen.</p> -<p><a href="https://rnemeth90.github.io/images/gh-actions-2.png"><img src="https://rnemeth90.github.io/images/gh-actions-2.png" alt=""></a></p> - + http://localhost:1313/posts/2022-12-24-gh-actions-copy/ + In this article, we&rsquo;ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app written in any language though. We&rsquo;ll cover the following: What are github actions? Setting up the workflow to build, test, and deploy a binary Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. - Continuous Deployment Models - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ + http://localhost:1313/posts/2022-01-14-continuous-deployment-models/ Fri, 14 Jan 2022 19:24:01 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ - <p>When deploying new software releases to servers or (insert -as-a-service&gt; here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments.</p> -<h2 id="bluegreen-deployments" >Blue/Green Deployments -<span> - <a href="#bluegreen-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. Instead, it gets deployed to another set of servers (blue) first. Since the blue servers are not currently serving any traffic for users, the deployment has no impact. However, once the deployment has been completed successfully and tested, users will be directed to the new deployment (blue). You can control all user traffic or a subset of user traffic if your load balancer supports it (referred to as ‘Progressive Exposure’).</p> -<p>The next release will then repeat the same process. Blue would be the current production environment, so you would first deploy to the green servers. This model requires two sets of identical hosts and a load balancer or reverse proxy in front of them. If there are any unexpected issues with the new release, it is straightforward to switch back to the previous release. The disadvantage to this type of model is that it requires having redundant environments (and potentially wasted resources). However, this is less of a concern if using container orchestration platforms such as Kubernetes.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/01/2022-01-19_07h57_58-1024x575.png" alt="Blue Green deployment model"></p> -<h2 id="immutable-servers" >Immutable Servers -<span> - <a href="#immutable-servers"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>There is an alternative method of blue/green deployments called “immutable servers”. This method is identical to blue/green deployments as described above. However, after switching user traffic over to the servers with the new release, the old servers are destroyed. They are not used again. This type of model becomes particularly efficient when using a pipeline that is capable of creating servers for you (i.e., Azure DevOps Pipelines)</p> -<h2 id="canary-deployments" >Canary Deployments -<span> - <a href="#canary-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>In a canary deployment, not all users are routed to the new release immediately. Only a limited percentage of users get access to the new release. These users are the canaries. They should be monitored closely, so it is important to be using Not all users are routed to the new release immediately in a canary deployment. Only a limited percentage of users get access to the latest release. These users are the canaries.</p> -<p>Organizations should monitor the canaries closely, so it is essential to be using monitoring software capable of looking at the statistics of a web application from the users’ perspective (for example, Application Insights). The number of canaries can increase until all traffic is directed to the new release over time. The most significant advantage of this method is limited exposure to issues. If a problem appears after the release is deployed, only a small subset of users will experience it. After you fix the issues and redeploy the release, it’s best to select a different group of users to be canaries.</p> -<h2 id="ring-based-deployments" >Ring Based Deployments -<span> - <a href="#ring-based-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>A ring-based deployment has multiple production environments. Each serves a limited number of users, similar to a canary deployment. However, you can have as many production environments as you want with a ring-based deployment. New releases are deployed to the rings one by one over time.</p> -<h2 id="feature-flag-deployments" >Feature Flag Deployments -<span> - <a href="#feature-flag-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Feature flags are used to expose new features to sets of users slowly. Unlike the other deployment models, they are not implemented in the infrastructure. Instead, they are typically implemented and enabled in code or database. An example would be a feature flag in a database that gives users access to a button on your web page. A developer could enable the flag for a set of users. These users would be able to see the button; other users would not. Feature flags can even toggle bug fixes or performance improvements.</p> -<p>I will cover implementing blue/green deployments in Azure using Azure DevOps and App Services in a future article.</p> - + http://localhost:1313/posts/2022-01-14-continuous-deployment-models/ + When deploying new software releases to servers or (insert -as-a-service&gt; here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments. Blue/Green Deployments Link to heading Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. - diff --git a/public/tags/ci/cd/page/1/index.html b/public/tags/ci/cd/page/1/index.html index 6b300a42..0b69dfd8 100644 --- a/public/tags/ci/cd/page/1/index.html +++ b/public/tags/ci/cd/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/ci/cd/ - + http://localhost:1313/tags/ci/cd/ + - + diff --git a/public/tags/cisco/index.html b/public/tags/cisco/index.html index 2245d5a1..9d72fa59 100644 --- a/public/tags/cisco/index.html +++ b/public/tags/cisco/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Cisco · GeekyRyan + - - -Cisco - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,293 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Tag: Cisco

    - - - -
    -
    -
    -

    Cisco AnyConnect &#8211; VPN Establishment Capability from a Remote Desktop is Disabled

    -
    -
    +
    +
    + © -
    - I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution. -Upon installation, AnyConnect pulls down a profile from the ASA containing several settings. This profile is in xml format and is located (on a Windows machine) at %programdata%CiscoCisco AnyConnect Secure Mobility ClientProfileAnyConnectProfile.xsd. -To resolve this issue and connect to your VPN, open this file with notepad (or any text editor, run as admin), search for the “WindowsVPNEstablishment” tag, and modify the value. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/cisco/index.xml b/public/tags/cisco/index.xml index 6bebb275..a102c827 100644 --- a/public/tags/cisco/index.xml +++ b/public/tags/cisco/index.xml @@ -2,31 +2,18 @@ Cisco on GeekyRyan - https://rnemeth90.github.io/tags/cisco/ - GeekyRyan (Cisco) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/cisco/ + Recent content in Cisco on GeekyRyan + Hugo + en Wed, 07 Oct 2020 13:28:00 +0000 - - - - + Cisco AnyConnect &#8211; VPN Establishment Capability from a Remote Desktop is Disabled - https://rnemeth90.github.io/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ + http://localhost:1313/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ Wed, 07 Oct 2020 13:28:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ - <p>I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution.</p> -<p><a href="https://lh3.googleusercontent.com/-BYApW8vZjV8/X33B2Or4D7I/AAAAAAAAxuY/hWQwpE-fqo4xInAsx9vyUvzDJXqxe68QQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-16.png" alt=""></a></p> -<p>Upon installation, AnyConnect pulls down a profile from the ASA containing several settings. This profile is in xml format and is located (on a Windows machine) at %programdata%CiscoCisco AnyConnect Secure Mobility ClientProfileAnyConnectProfile.xsd.</p> -<p>To resolve this issue and connect to your VPN, open this file with notepad (or any text editor, run as admin), search for the “WindowsVPNEstablishment” tag, and modify the value. The default value is “LocalUsersOnly”, you will need to change it to “AllowRemoteUsers”. Save and close the file, then restart the machine.</p> -<p>BEFORE:</p> -<p><a href="https://lh3.googleusercontent.com/-izGUUyhtWyM/X33Bh8YdqGI/AAAAAAAAxuQ/rBbXsqWhe5wZYoGmjXwyyidGmu1kCNVmgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-17.png" alt=""></a></p> -<p>AFTER:</p> -<p><a href="https://lh3.googleusercontent.com/-wFFu1JOXymQ/X33CVp0cImI/AAAAAAAAxug/fibXC6JHmkkilFtWv8641x20flapCibYACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-18.png" alt=""></a></p> - + http://localhost:1313/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ + I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution. Upon installation, AnyConnect pulls down a profile from the ASA containing several settings. This profile is in xml format and is located (on a Windows machine) at %programdata%CiscoCisco AnyConnect Secure Mobility ClientProfileAnyConnectProfile.xsd. To resolve this issue and connect to your VPN, open this file with notepad (or any text editor, run as admin), search for the “WindowsVPNEstablishment” tag, and modify the value. - diff --git a/public/tags/cisco/page/1/index.html b/public/tags/cisco/page/1/index.html index 6cb45db6..836ef188 100644 --- a/public/tags/cisco/page/1/index.html +++ b/public/tags/cisco/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/cisco/ - + http://localhost:1313/tags/cisco/ + - + diff --git a/public/tags/database/index.html b/public/tags/database/index.html index 54d3d933..d98a5fad 100644 --- a/public/tags/database/index.html +++ b/public/tags/database/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Database · GeekyRyan + - - -database - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,306 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Tag: database

    - - - -
    -
    -
    -

    EF Core &#8211; Unable to create an object of type DbContext

    -
    -
    +
    +
    + © -
    - This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it! -When running EF Core migrations in a solution, you may come across this error: -There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio. -To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/database/index.xml b/public/tags/database/index.xml index 9631c5b1..41a99872 100644 --- a/public/tags/database/index.xml +++ b/public/tags/database/index.xml @@ -1,32 +1,19 @@ - database on GeekyRyan - https://rnemeth90.github.io/tags/database/ - GeekyRyan (database) - Hugo -- gohugo.io - en-us + Database on GeekyRyan + http://localhost:1313/tags/database/ + Recent content in Database on GeekyRyan + Hugo + en Sun, 12 Jun 2022 13:58:52 +0000 - - - - + EF Core &#8211; Unable to create an object of type DbContext - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ Sun, 12 Jun 2022 13:58:52 +0000 - - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ - <p>This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it!</p> -<p>When running EF Core migrations in a solution, you may come across this error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-1-1024x142.png"></a></p> -<p>There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio.</p> -<p>To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-2.png"></a></p> -<p>If you are using clean architecture, or some other architecture that has your startup context and your dbContext in different projects, you will need to set your startup project to your runtime, and the ‘Default Project’ in the package manager console to the project containing your dbContext.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-3-1024x493.png"></a></p> - + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it! When running EF Core migrations in a solution, you may come across this error: There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio. To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’. - diff --git a/public/tags/database/page/1/index.html b/public/tags/database/page/1/index.html index d03a9427..7e3487c6 100644 --- a/public/tags/database/page/1/index.html +++ b/public/tags/database/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/database/ - + http://localhost:1313/tags/database/ + - + diff --git a/public/tags/dev/index.html b/public/tags/dev/index.html index cb52d405..33c02fca 100644 --- a/public/tags/dev/index.html +++ b/public/tags/dev/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Dev · GeekyRyan + - - -Dev - GeekyRyan - - - + - - - + + + - - + + + + + + + + + - + + + + - - - - - - - - - - - - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,442 +79,166 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - + + + - - - - - - - - -
    -
    - -

    Tag: Dev

    - - - -
    -
    -
    -

    Use “replace” in go.mod to Point to a Local Module

    -
    - -
    - - -
    - If you want to the local version of a dependency in Go rather than one in a remote repository, use the replace keyword. -The replace line goes above your require statements, like so: -module github.com/rnemeth90/foo replace github.com/rnemeth90/bar => /Users/rnemeth90/Projects/bar require ( github.com/rnemeth90/bar v1.0.0 ) Now when you compile this module go build or go install, it will use your local code rather than the remote dependency. -According to the docs, you do need to make sure that the code you’re pointing to also has a go. -
    - - -
    - Read more -
    - - - +
    + + + +
    +
  • + 2022-07-21 + Reading Json Files with Go +
  • -
    -
    -
    -

    Powershell for Devops - Querying REST APIs with Powershell

    -
    - -
    + + - -
    - This will be a short post on querying REST APIs with Powershell. -It’s hard to argue that REST APIs are the predominant technology for interacting with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) product without having to go through the exercise of a more complicated integration. REST APIs communicate in a common format, typically JSON. However, most will allow us to choose the response format by specifying an option in the ‘Accept’ header. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Reading Json Files with Go

    -
    -
    +
    +
    + © -
    - JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting with it, and most public APIs accept JSON in HTTP requests. -In this post, we’ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the JSON data within the file into a memory structure. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - +
    +
    +
    - + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/tags/dev/index.xml b/public/tags/dev/index.xml index 9055b893..0cf5c14a 100644 --- a/public/tags/dev/index.xml +++ b/public/tags/dev/index.xml @@ -2,218 +2,32 @@ Dev on GeekyRyan - https://rnemeth90.github.io/tags/dev/ - GeekyRyan (Dev) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/dev/ + Recent content in Dev on GeekyRyan + Hugo + en Tue, 06 Sep 2022 00:00:00 +0000 - - - - + Use “replace” in go.mod to Point to a Local Module - https://rnemeth90.github.io/posts/2022-09-06-go-mod-replace-copy/ + http://localhost:1313/posts/2022-09-06-go-mod-replace-copy/ Tue, 06 Sep 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-09-06-go-mod-replace-copy/ - <p>If you want to the local version of a dependency in Go rather than one in a remote repository, use the <em>replace</em> keyword.</p> -<p>The replace line goes above your require statements, like so:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> module github.com/rnemeth90/foo -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> replace github.com/rnemeth90/bar <span style="color:#f92672">=</span>&gt; /Users/rnemeth90/Projects/bar -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> require <span style="color:#f92672">(</span> -</span></span><span style="display:flex;"><span> github.com/rnemeth90/bar v1.0.0 -</span></span><span style="display:flex;"><span> <span style="color:#f92672">)</span> -</span></span></code></pre></div><p>Now when you compile this module <em>go build</em> or <em>go install</em>, it will use your local code rather than the remote dependency.</p> -<p>According to the docs, you do need to make sure that the code you’re pointing to also has a <strong>go.mod</strong> file:</p> -<blockquote> -<p><strong>Note</strong>: if the right-hand side of a <code>replace</code> directive is a filesystem path, then the target must have a <code>go.mod</code> file at that location. If the <code>go.mod</code> file is not present, you can create one with <code>go mod init</code>.</p> -<p><a href="https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive">https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive</a></p> -</blockquote> -<p>You can also create this line from the command line using the <strong>go mod edit</strong> command.</p> -<pre><code>$ go mod edit -replace github.com/rnemeth90/bar=/Users/rnemeth90/Projects/bar -</code></pre> -<p>Following the <strong>-replace</strong> is first what you want to replace, then an equals sign, then what you’re replacing it with.</p> -<p>Hopefully this helps someone who was stuck with this like me 🙂</p> - + http://localhost:1313/posts/2022-09-06-go-mod-replace-copy/ + If you want to the local version of a dependency in Go rather than one in a remote repository, use the replace keyword. The replace line goes above your require statements, like so: module github.com/rnemeth90/foo replace github.com/rnemeth90/bar =&gt; /Users/rnemeth90/Projects/bar require ( github.com/rnemeth90/bar v1.0.0 ) Now when you compile this module go build or go install, it will use your local code rather than the remote dependency. According to the docs, you do need to make sure that the code you’re pointing to also has a go. - Powershell for Devops - Querying REST APIs with Powershell - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ Thu, 04 Aug 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ - <p>This will be a short post on querying REST APIs with Powershell.</p> -<p>It&rsquo;s hard to argue that REST APIs are the predominant technology for interacting -with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) -product without having to go through the exercise of a more complicated integration. REST APIs communicate -in a common format, typically JSON. However, most will allow us to choose the response format by specifying an -option in the &lsquo;Accept&rsquo; header. Most languages provide a native method for interacting with -REST APIs. This objective for this post is to show you how simple this is with Powershell.</p> -<p>To get started, we&rsquo;ll need a public API to interact with. I&rsquo;m going to use <a href="https://icanhazdadjoke.com/">https://icanhazdadjoke.com/</a>, because -there is no authentication and no rate-limiting (two concepts we will cover in another post).</p> -<p>Calling the API is extremely simple:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -</span></span></code></pre></div><p>However, this results in the content being returned as plain text. This isn&rsquo;t ideal.</p> -<p>Let&rsquo;s pass the &lsquo;Accept&rsquo; header to tell the API the format we are expecting to be returned:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers -</span></span></code></pre></div><p>Output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>[<span style="color:#ae81ff">15</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">04</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">34</span>] C:\..\..\rnemeth90.github.io on <span style="color:#960050;background-color:#1e0010"></span>main <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#ae81ff">+1</span> <span style="color:#960050;background-color:#1e0010">❯</span> Invoke-RestMethod -Uri $url -Method Get -Headers $headers -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>id joke status -</span></span><span style="display:flex;"><span>-- ---- ------ -</span></span><span style="display:flex;"><span>3LmyXvsPfqc I don<span style="color:#e6db74">&#39;t trust stairs. They&#39;</span>re always up to something. <span style="color:#ae81ff">200</span> -</span></span></code></pre></div><p>That looks a little better. For those of you familiar with Powershell, the output above probably -looks completely normal. But for those not-so-familiar with Powershell, or those expecting -more of a &lsquo;json-esk&rsquo; output, this may look a bit&hellip; weird.</p> -<p>Powershell is an object oriented language. <strong>Everything is an object</strong> in Powershell, even the response -of this request. What you see in the output is simply the properties of the object.</p> -<p>Luckily Powershell provides us with a cmdlet to convert an object into json (aptly named: ConvertTo-Json). We can use it like this:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers | ConvertTo-Json -</span></span></code></pre></div><p>Here we are piping the output from Invoke-RestMethod to ConvertTo-Json. Pretty neat!</p> -<p>Output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>[<span style="color:#ae81ff">15</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">04</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">35</span>] C:\..\..\rnemeth90.github.io on <span style="color:#960050;background-color:#1e0010"></span>main <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#ae81ff">+1</span> <span style="color:#960050;background-color:#1e0010">❯</span> Invoke-RestMethod -Uri $url -Method Get -Headers $headers | Convertto-json -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;id&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#e6db74">&#34;AAdFBXnGlyd&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;joke&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#e6db74">&#34;If you walk into a forest and cut down a tree, but the tree doesn&#39;t understand why you cut it down, do you think it&#39;s stumped?&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;status&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#ae81ff">200</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Now, that looks more normal.</p> -<p>There is much more we can do with Invoke-RestMethod. The &lsquo;Method&rsquo; parameter of this cmdlet accepts any of the common -HTTP methods (GET, PUT, PATCH, DELETE, POST, HEAD). You can also specify other headers and a body (using the -body parameter).</p> -<p>Both of these parameters accept dictionaries:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Host&#39;</span> = <span style="color:#e6db74">&#39;MyServer&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>$body = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Eat&#39;</span> = <span style="color:#e6db74">&#39;Pizza&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers -Body $body | ConvertTo-Json -</span></span></code></pre></div><p>Unfortunately I won&rsquo;t be able to show the other HTTP methods, as this API only supports GET requests. So that&rsquo;s all for now.</p> - + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ + This will be a short post on querying REST APIs with Powershell. It&rsquo;s hard to argue that REST APIs are the predominant technology for interacting with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) product without having to go through the exercise of a more complicated integration. REST APIs communicate in a common format, typically JSON. However, most will allow us to choose the response format by specifying an option in the &lsquo;Accept&rsquo; header. - Reading Json Files with Go - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ + http://localhost:1313/posts/2022-07-21-reading-json-files-with-go/ Thu, 21 Jul 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ - <p>JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting -with it, and most public APIs accept JSON in HTTP requests.</p> -<p>In this post, we&rsquo;ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the -JSON data within the file into a memory structure.</p> -<p>Let&rsquo;s assume we have the following JSON data representing an employee:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">1</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Steve&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Rogers&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Captain America&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Department&#34;</span>: <span style="color:#e6db74">&#34;Avengers&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>We need a way of representing this data in memory when decoding it from JSON. For this, we will need to create a struct:</p> -<p>We will build up our go module as we progress through the article</p> -<p>Let&rsquo;s start:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#75715e">// main.go -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> ( -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;encoding/json&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;fmt&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;io/ioutil&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;log&#34;</span> -</span></span><span style="display:flex;"><span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">// Hero represents an hero -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// ALL fields must be exportable! Otherwise the JSON parsing will fail. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Hero</span> <span style="color:#66d9ef">struct</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Id</span> <span style="color:#66d9ef">int</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">FirstName</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">LastName</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Alias</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Group</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() { -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Here we set the log prefix. When reading stack traces, this makes it easier to know -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// where a failure occurred. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">SetPrefix</span>(<span style="color:#e6db74">&#34;main(): &#34;</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// We first need to load the JSON file into memory -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">content</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">ioutil</span>.<span style="color:#a6e22e">ReadFile</span>(<span style="color:#e6db74">&#34;./heros.json&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#e6db74">&#34;Error opening the file: &#34;</span>, <span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Now we parse the JSON data into a memory structure. We know our JSON file will have more than one hero object, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// so we&#39;ll use make() to create a []Hero slice. Since go is a pass-by-value language, we will then use the address-of -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// operator (&amp;) to unmarshal our json data into the heros slice -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">heros</span> <span style="color:#f92672">:=</span> make([]<span style="color:#a6e22e">Hero</span>, <span style="color:#ae81ff">5</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">json</span>.<span style="color:#a6e22e">Unmarshal</span>(<span style="color:#a6e22e">content</span>, <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">heros</span>) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#e6db74">&#34;Error occurred during unmarshal: &#34;</span>, <span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// now we can read/interact with the data. We&#39;ll loop over the array -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// and print the values in memory -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; len(<span style="color:#a6e22e">heros</span>); <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">Id</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">FirstName</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">LastName</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">Group</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Create a file named employees.json with similar data:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>[ -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">1</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Steve&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Rogers&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Captain America&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;group&#34;</span>: <span style="color:#e6db74">&#34;Avengers&#34;</span> -</span></span><span style="display:flex;"><span> }, -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">2</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Clark&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Kent&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Superman&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;group&#34;</span>: <span style="color:#e6db74">&#34;Justice League&#34;</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>] -</span></span></code></pre></div><p>Now, we can run our main.go file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>11:40:47 ryan@xerxes json → go run main.go -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>Steve -</span></span><span style="display:flex;"><span>Rogers -</span></span><span style="display:flex;"><span>Avengers -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span>Clark -</span></span><span style="display:flex;"><span>Kent -</span></span><span style="display:flex;"><span>Justice League -</span></span><span style="display:flex;"><span>11:40:49 ryan@xerxes json -</span></span></code></pre></div><p>Pretty simple! That&rsquo;s why I love go. We accomplished all of this with ~50 lines of code. -Doing something similar in asp.net project would easily double that count and involve creating -multiple files! (nothing against asp.net or c#, I think c# is a great language and use it daily)</p> -<p>Now, &lsquo;go&rsquo; try this!</p> - + http://localhost:1313/posts/2022-07-21-reading-json-files-with-go/ + JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting with it, and most public APIs accept JSON in HTTP requests. In this post, we&rsquo;ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the JSON data within the file into a memory structure. - diff --git a/public/tags/dev/page/1/index.html b/public/tags/dev/page/1/index.html index 402b4feb..b42432f9 100644 --- a/public/tags/dev/page/1/index.html +++ b/public/tags/dev/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/dev/ - + http://localhost:1313/tags/dev/ + - + diff --git a/public/tags/devops/index.html b/public/tags/devops/index.html index fa37b23e..283c2fc8 100644 --- a/public/tags/devops/index.html +++ b/public/tags/devops/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Devops · GeekyRyan + - - -devops - GeekyRyan - - - - - - - - - - - + - - + + + - + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,932 +79,232 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - - -
    -
    - -

    Tag: devops

    - - - -
    -
    -
    -

    Using try/catch/finally Blocks in PowerShell

    -
    - -
    - - -
    - Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it’s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we’ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn’t crash when the unexpected occurs. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Golang: When Identical Strings are Not Equal

    -
    - -
    - - -
    - This will be a quick and dirty post, so please forgive any spelling/grammar mistakes. -I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don’t write a ton of code at work (mostly just scripting/pipelines when I do), so I’m constantly working on something like this in my spare time. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Handling Graceful Shutdown in a .NET App Hosted in Kubernetes

    -
    - -
    - - -
    - I was recently involved with troubleshooting some API’s hosted in Kubernetes throwing http/502’s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Chaining YAML Pipelines in Azure Devops

    -
    - -
    - - -
    - In this article, we’ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to figure this out. -Our two pipelines will exist in the same repository. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Update Azure Devops SPN Secret

    -
    - -
    - - -
    - If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal. -In this article, I’ll show you two methods for updating a secret for a service principal prior to expiration. -Update the secret via the Azure Devops Portal: Go to “Service Connections” in the Azure Devops portal Find the SPN you want to update, then click “Manage Service Principal” Then on the service principal page, click Certificates & Secrets Create a “New Client Secret”, take note of the value Delete the ‘old’ secret Return to the Service Connection in the Azure Devops portal Click Edit - click the verify button. -
    - - -
    - Read more -
    - - - - -
    - -
    -
    -
    -

    Running Docker in WSL v1

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Tag: Devops +

    +
    + +
    +
  • + 2024-06-29 + Mounting Multiple Kubernetes Secrets into One Directory +
  • -
    -
    -
    -

    Accessing Secrets Securely in Azure DevOps Pipelines

    -
    - -
    - +
  • + 2023-08-15 + Using try/catch/finally Blocks in PowerShell +
  • -
    - This post will cover a secure method for accessing secrets in Azure DevOps pipelines. -Why Azure Key Vault? Azure Key Vault is an Azure cloud service used to securely store secrets, keys, and certificates. A secret can be any string of characters, such as API keys, passwords, URLs, etc. Azure Key Vault encrypts data at rest and in transit using HTTPS. Depending on the type of Key Vault you are using, data at rest is encrypted using software encryption (AES 256) or HSM-backed keys. -
    +
  • + 2023-01-24 + Golang: When Identical Strings are Not Equal +
  • +
  • + 2022-12-28 + Handling Graceful Shutdown in a .NET App Hosted in Kubernetes +
  • -
    - Read more -
    +
  • + 2022-11-03 + Chaining YAML Pipelines in Azure Devops +
  • +
  • + 2022-09-12 + Update Azure Devops SPN Secret +
  • +
  • + 2022-06-26 + Running Docker in WSL v1 +
  • - +
  • + 2022-02-19 + Accessing Secrets Securely in Azure DevOps Pipelines +
  • - - - -
    - -
    -
    -
    -

    Kubernetes Pod Eviction

    -
    - -
    +
    + -
    -
    -
    -

    Continuous Deployment Models

    -
    - -
    - -
    - When deploying new software releases to servers or (insert -as-a-service> here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments. -Blue/Green Deployments Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. Instead, it gets deployed to another set of servers (blue) first. -
    + +
  • 1
  • + + -
    - Read more -
    + - + +
  • 2
  • + - - - -
    - -
    -
    -
    -

    Deploy Azure VMs Using Azure Devops CI/CD Pipeline

    -
    -
    +
    +
    + © -
    - This article assumes that you have already created a pipeline in Azure Devops and have it linked to an Azure Devops repo. You will need to create a variable named $vmpassword and assign it the value stored in your key vault. -To create a release pipeline that will automatically create a VM (using the password stored in key vault for the local administrator account), do the following: -Create a new release pipeline 3. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - - -
    +
    - https://rnemeth90.github.io/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ - Ryan +
    + -
    - - - - - - -
    -
    + + + + - - - - - - + + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/devops/index.xml b/public/tags/devops/index.xml index 30401ba0..7e7d7124 100644 --- a/public/tags/devops/index.xml +++ b/public/tags/devops/index.xml @@ -1,762 +1,96 @@ - devops on GeekyRyan - https://rnemeth90.github.io/tags/devops/ - GeekyRyan (devops) - Hugo -- gohugo.io - en-us - Tue, 15 Aug 2023 00:00:00 +0000 - - - - + Devops on GeekyRyan + http://localhost:1313/tags/devops/ + Recent content in Devops on GeekyRyan + Hugo + en + Sat, 29 Jun 2024 00:00:00 +0000 + + + Mounting Multiple Kubernetes Secrets into One Directory + http://localhost:1313/posts/2024-06-29-mount-multiple-kubernetes-secrets-into-one-directory/ + Sat, 29 Jun 2024 00:00:00 +0000 + http://localhost:1313/posts/2024-06-29-mount-multiple-kubernetes-secrets-into-one-directory/ + Introduction Link to heading Combining multiple Kubernetes secrets into a single directory can streamline secret management in your applications. This guide walks you through the process of achieving this in Kubernetes, ensuring efficient and organized secret management. Creating Secrets Link to heading First, create your secrets using the kubectl create secret command: kubectl create secret generic secret-one --from-literal=key1=value1 kubectl create secret generic secret-two --from-literal=key2=value2 Each secret can contain multiple key-value pairs, and you can add more secrets as needed. + Using try/catch/finally Blocks in PowerShell - https://rnemeth90.github.io/posts/2023-08-15-powershell-try-catch/ + http://localhost:1313/posts/2023-08-15-powershell-try-catch/ Tue, 15 Aug 2023 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2023-08-15-powershell-try-catch/ - <p>Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it&rsquo;s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we&rsquo;ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn&rsquo;t crash when the unexpected occurs. We&rsquo;ll then cover the differences in terminating and non-terminating errors and why you should take these into consideration when implementing error handling.</p> -<h2 id="the-try-block" >The Try Block -<span> - <a href="#the-try-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The Try block is where you place the code that might generate an error. Think of it as a protective bubble around your potentially troublesome code. If an error occurs within the Try block, PowerShell will immediately jump to the corresponding Catch block.</p> -<p>Here&rsquo;s a simple example:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><h2 id="the-catch-block" >The Catch Block -<span> - <a href="#the-catch-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The Catch block is where you can handle the error. PowerShell provides you with a special variable $_ that contains information about the error. You can use this variable to display error messages or even take corrective actions.</p> -<p>In the example above, we&rsquo;re capturing the error generated by attempting to retrieve a nonexistent file. The $_ variable holds the error message, which we&rsquo;re displaying using Write-Host.</p> -<h2 id="the-finally-block" >The Finally Block -<span> - <a href="#the-finally-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Now, let&rsquo;s talk about the unsung hero – the Finally block. This block is executed regardless of whether an error occurred or not. It&rsquo;s where you can place cleanup code that ensures your script leaves no trace behind, even in the face of adversity. Some tasks that are commonly done in the finally block are closing database connections, removing temp files, etc. The finally block is completely optional.</p> -<pre tabindex="0"><code> -try { - # Code that might generate an error - # ... -} -catch { - # Code to handle the error - # ... -} -finally { - # Cleanup code here - # ... -} -</code></pre><h2 id="terminatingnon-terminating-errors" >Terminating/non-terminating Errors -<span> - <a href="#terminatingnon-terminating-errors"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>non-terminating errors are any error that will not stop the execution of your script. Most cmdlets in PowerShell are non-terminating. They may output an error, but your script will continue to run. These kinds of errors cannot be caught with a catch block by default. The reason for this is the default <code>ErrorAction</code> in your PowerShell profile, which is set to <code>Continue</code>.</p> -<pre tabindex="0"><code># To show your default error action type -$ErrorActionPreference -</code></pre><p>Let&rsquo;s go back and look at our first example:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><p>If you took the time to run this code, you may have noticed that the <code>Write-Host</code> cmdlet in the <code>catch</code> block was never ran. Why did we get a red error message in our PowerShell console, rather than the text <code>An error occurred: ...</code>? The reason is that the non-existing path isn&rsquo;t a terminating error, and the default <code>ErrorAction</code> is <code>Continue</code>. To catch the error, you will need to change the <code>ErrorAction</code> in your PowerShell console to <code>Stop</code>. This can be done in multiple ways. You can add <code>-ErrorAction Stop</code> to the cmdlet, like this:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -ErrorAction Stop -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><p>Or you can change the <code>ErrorActionPreference</code> for the entire script, by adding this to the top of the script:</p> -<pre tabindex="0"><code>$ErrorActionPreference = &#34;Stop&#34; -</code></pre><h2 id="exceptions" >Exceptions -<span> - <a href="#exceptions"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>If you have ever worked with exceptions in C# you can skip this section. In the previous examples, we used simple <code>catch</code> blocks that will catch <em>any</em> error. This is a good start, but we can do better. PowerShell allows you to catch individual exceptions based on the exception type, similar to how C# handles catching exceptions.</p> -<p>Let&rsquo;s look at an example:</p> -<pre tabindex="0"><code>try { - # Attempt to open a non-existent file - $file = Get-Content -Path &#34;NonexistentFile.txt&#34; -} -catch [System.IO.FileNotFoundException] { - Write-Host &#34;Caught a FileNotFoundException: $_&#34; -} -catch { - Write-Host &#34;Caught an exception: $_&#34; -} -</code></pre><p>We now have two <code>catch</code> blocks. If we encounter an exception of type <code>System.IO.FileNotFoundException</code>, the first <code>catch</code> block will catch the exception and handle it accordingly. The second <code>catch</code> block will handle any other generic error.</p> -<h2 id="conclusion" >Conclusion -<span> - <a href="#conclusion"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Error handling might seem daunting at first, but with the power of Try-Catch-Finally blocks at your fingertips, you&rsquo;re well-equipped to handle errors gracefully and ensure the resilience of your PowerShell scripts. Remember, every error is an opportunity to refine your skills and make your scripts more robust.</p> -<p>Thanks for reading!</p> -<p>Official Microsoft Documentation for Try-Catch-Finally in PowerShell: -<a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-7.3">about_try_catch_finally</a></p> - + http://localhost:1313/posts/2023-08-15-powershell-try-catch/ + Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it&rsquo;s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we&rsquo;ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn&rsquo;t crash when the unexpected occurs. - Golang: When Identical Strings are Not Equal - https://rnemeth90.github.io/posts/2023-01-24-golang-strings-not-equal/ + http://localhost:1313/posts/2023-01-24-golang-strings-not-equal/ Tue, 24 Jan 2023 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2023-01-24-golang-strings-not-equal/ - <p><em>This will be a quick and dirty post, so please forgive any spelling/grammar mistakes.</em></p> -<p>I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don&rsquo;t write a ton of code at work (mostly just scripting/pipelines when I do), so I&rsquo;m constantly working on something like this in my spare time. Anyway, I was writing this app, got everything working like I wanted it to. I then wrote some of the tests and was iterating over them. I noticed the <code>ListTasks</code> test was failing:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TestAddTask</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">task</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;test task number 1&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Getwd</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmdPath</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">binaryName</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;AddNewTask&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-add&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">Run</span>(); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// failing test -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;ListTasks&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-list&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">out</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">CombinedOutput</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">expected</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;[ ] 1: %s&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Compare</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#a6e22e">expected</span>) <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;got %v, expected %v\n&#34;</span>, <span style="color:#a6e22e">out</span>, []byte(<span style="color:#a6e22e">expected</span>)) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Seems strange, considering the strings appear to be equivalent in the output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span> main_test.go:82: got <span style="color:#f92672">[</span> <span style="color:#f92672">]</span> 1: test task number <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> , expected <span style="color:#f92672">[</span> <span style="color:#f92672">]</span> 1: test task number <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>--- FAIL: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- FAIL: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>FAIL -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>exit status <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>FAIL github.com/rnemeth90/todo/cmd/todo 0.105s -</span></span></code></pre></div><p>What could be happening? After banging my head on the desk a few times, a revelation came to me&hellip;</p> -<p>In Go, strings are simply slices of bytes. I decided to print out each string as a byte array:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span> main_test.go:80: got <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">10</span> 10<span style="color:#f92672">]</span>, expected <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> 49<span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span>--- FAIL: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- FAIL: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>FAIL -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>exit status <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>FAIL github.com/rnemeth90/todo/cmd/todo 0.144s -</span></span></code></pre></div><p>Let&rsquo;s take a closer look at the byte arrays from the test output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>got <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">10</span> 10<span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span>expected <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> 49<span style="color:#f92672">]</span> -</span></span></code></pre></div><p>We can see the byte array returned from <code>cmd.CombinedOutput()</code> has some additional bytes in it at the end (32,10,10). What exactly are 32, 10, and 10? To figure this out, I went over to the go playground: <a href="https://go.dev/play/">https://go.dev/play/</a>.</p> -<p>Let&rsquo;s see what happens when we create a byte array with a single number and print it out as a string to the console:</p> -<p><a href="https://rnemeth90.github.io/images/golang-strings-not-equal-01.png"><img src="https://rnemeth90.github.io/images/golang-strings-not-equal-01.png" alt=""></a></p> -<p>Interesting, we can see that <code>m</code> was output to the console. So what do our mysterious additional characters in our test result represent? Let&rsquo;s see:</p> -<p><a href="https://rnemeth90.github.io/images/golang-strings-not-equal-02.png"><img src="https://rnemeth90.github.io/images/golang-strings-not-equal-02.png" alt=""></a></p> -<p>It&rsquo;s hard to tell from the output, but if you look in the results pane, you&rsquo;ll see a space and two new lines. So <code>32</code> represents a space, and <code>10</code> represents a new line!</p> -<p>You can play with this code yourself: <a href="https://go.dev/play/p/fGUIxJM6KnV">https://go.dev/play/p/fGUIxJM6KnV</a></p> -<p>Ok, so let&rsquo;s fix our failing test:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TestAddTask</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">task</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;test task number 1&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Getwd</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmdPath</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">binaryName</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;AddNewTask&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-add&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">Run</span>(); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;ListTasks&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-list&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">out</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">CombinedOutput</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// add this line -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">out</span> = []byte(<span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">TrimSuffix</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#e6db74">&#34; \n\n&#34;</span>)) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">expected</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;[ ] 1: %s&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Compare</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#a6e22e">expected</span>) <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;got %v, expected %v\n&#34;</span>, <span style="color:#a6e22e">out</span>, []byte(<span style="color:#a6e22e">expected</span>)) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>The <code>strings</code> package has a <code>TrimSuffix</code> function that is useful for trimming bits off the end of a string. In the code above, you can see that we added <code>out = []byte(strings.TrimSuffix(string(out), &quot; \n\n&quot;))</code>, which will trim off the space (character 32) and the two new lines (character 10). Now when we run our integration test, it passes:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span>--- PASS: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>PASS -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>ok github.com/rnemeth90/todo/cmd/todo 0.106s -</span></span></code></pre></div> + http://localhost:1313/posts/2023-01-24-golang-strings-not-equal/ + This will be a quick and dirty post, so please forgive any spelling/grammar mistakes. I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don&rsquo;t write a ton of code at work (mostly just scripting/pipelines when I do), so I&rsquo;m constantly working on something like this in my spare time. - Handling Graceful Shutdown in a .NET App Hosted in Kubernetes - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ Wed, 28 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ - <p>I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. It was actually a combination of these blogs (and the resolutions posted) that ended up resolving our issue.</p> -<h3 id="so-what-was-actually-causing-the-502s" >So what was actually causing the 502&rsquo;s? -<span> - <a href="#so-what-was-actually-causing-the-502s"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h3><p>As stated, these APIs are hosted in Kubernetes. They are written primarily in c# (.NET Framework) and hosted in Windows Server Core containers. The pods are load balanced using a service, and we have an Nginx ingress on top of the service. Nothing fancy, just a typical setup that you may have seen or even built yourself. We implement automatic scaling for our replica sets using a standard Kubernetes-native HPA or Keda, depending on the app. We have autoscale rules defined for the pods. Our clusters are hosted in Azure Kubernetes Service, and we autoscale our node pools. So, there are several layers of scaling happening in our clusters at any given time. Occasionally, when a pod was handling a client request, Kubelet or a controller would come along and scale the pod in. We were initially under the belief that the <code>terminationGracePeriodSeconds</code> value within our deployment would allow the pod to continue running for the defined number of seconds. However, we were mistaken. This value tells Kubernetes to allow the application running within the pod some time to clean up. It does <em>not</em> tell the app to continue running for the defined number of seconds after it receives a sigterm signal. This logic actually needs to be implemented within the application itself, or with a prestop hook. The prestop method is <a href="https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/">well documented</a>, so I will not cover it here.</p> -<p>To implement this in a .NET Framework app running in Windows, you need to add this registry key to your container.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">RUN</span> reg add hklm<span style="color:#ae81ff">\s</span>ystem<span style="color:#ae81ff">\c</span>urrentcontrolset<span style="color:#ae81ff">\c</span>ontrol /v WaitToKillServiceTimeout /t REG_SZ /d <span style="color:#ae81ff">60000</span> /f<span style="color:#960050;background-color:#1e0010"> -</span></span></span></code></pre></div><p>This value tells Windows to wait a number of milliseconds before shutting down Normally, Windows only waits for 5 seconds (default) before shutting down any &lsquo;background&rsquo; processes. Windows forcibly shuts down processes after this period of time.</p> -<p>Next, in the startup class, we&rsquo;ll add the following code. I have added inline comments to explain.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c#" data-lang="c#"><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">namespace</span> MyApp.APIConsoleHost -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Program</span> -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Register the SetConsoleCtrlHandler function in kernel32.dll in the -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> application to capture CTRL_SHUTDOWN_EVENT events for resource reclamation -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e"> [DllImport(&#34;Kernel32&#34;)]</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">extern</span> <span style="color:#66d9ef">bool</span> SetConsoleCtrlHandler(HandlerRoutine handler, <span style="color:#66d9ef">bool</span> <span style="color:#66d9ef">add</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Define a delegate for our handler routine</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">delegate</span> <span style="color:#66d9ef">bool</span> HandlerRoutine(CtrlTypes ctrlType); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">volatile</span> ManualResetEvent _exitEvent = <span style="color:#66d9ef">new</span> ManualResetEvent(<span style="color:#66d9ef">false</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> HandlerRoutine _handler; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Define the event types that we want to handle when the application receives a SIGTERM -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_C_EVENT = 0, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_BREAK_EVENT = 1, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_CLOSE_EVENT = 2, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_LOGOFF_EVENT = 5, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_SHUTDOWN_EVENT = 6 -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">enum</span> CtrlTypes -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> CTRL_SHUTDOWN_EVENT = <span style="color:#ae81ff">6</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Here we are defining how we want to handle the shutdown -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We get a timeout value from an env variable named APP_SHUTDOWN_TIMEOUT -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> If that env variable is not found, we default to 60 seconds. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We then switch on our CtrlTypes enum and handle each value accordingly, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then return true. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">bool</span> ConsoleCtrlCheck(CtrlTypes ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> timeout = ConfigurationManager.AppSettings[<span style="color:#e6db74">&#34;APP_SHUTDOWN_TIMEOUT&#34;</span>]; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> (<span style="color:#66d9ef">string</span>.IsNullOrEmpty(timeout)) { timeout = <span style="color:#e6db74">&#34;60&#34;</span>; } -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">int</span> counter = <span style="color:#66d9ef">int</span>.Parse(timeout); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">switch</span> (ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> CtrlTypes.CTRL_SHUTDOWN_EVENT: -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] CTRL_SHUTDOWN received&#34;</span>); -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] Web Server is stopping in {counter} seconds&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">while</span> (counter &gt; <span style="color:#ae81ff">0</span>) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> Thread.Sleep(TimeSpan.FromSeconds(<span style="color:#ae81ff">1</span>)); -</span></span><span style="display:flex;"><span> counter--; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.Set(); -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span>; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span>: -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">false</span>; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Our main method is pretty standard. However, we first register a new handler (_handler), -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then pass it to to the SetConsoleCtrlHandler() method we imported from Kernel32.dll. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> The only other &#39;unique&#39; thing is the _exitEvent.WaitOne(); call defined at the bottom of main(). -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> This is necessary so that main does not immediately exit, and wait&#39;s for a signal. We defined a -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> property for this _exitEvent of type ManualResetEvent at the top of this class file. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> Main(<span style="color:#66d9ef">string</span>[] args) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> _handler += <span style="color:#66d9ef">new</span> HandlerRoutine(ConsoleCtrlCheck); -</span></span><span style="display:flex;"><span> SetConsoleCtrlHandler(_handler, <span style="color:#66d9ef">true</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = BuildStartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> WebApp.Start&lt;SelfHostStartup&gt;(startOptions); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">&#34;Press CTRL+C to stop it&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.WaitOne(); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> StartOptions BuildStartOptions() -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = <span style="color:#66d9ef">new</span> StartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted start options</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> startOptions; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>To prevent the HandlerRoutine instance from being recycled by the GC before the program exits, the HandlerRoutine must be static (as seen in the above example). This is important because if the handlerroutine is recycled before the application is finished, it will throw an error, as shown here:</p> -<pre tabindex="0"><code>A callback was made on a garbage collected delegate of type &#39;Program+HandlerRoutine::Invoke&#39;. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called. -</code></pre> + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. - Chaining YAML Pipelines in Azure Devops - https://rnemeth90.github.io/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ + http://localhost:1313/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ Thu, 03 Nov 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ - <p>In this article, we&rsquo;ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. -Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to -figure this out.</p> -<p>Our two pipelines will exist in the same repository. We have a dependent-pipeline, that we only want to run once the source-pipeline is finished. This is useful if you have -some infrastructure you want to build, prior to deploying something to that infrastructure.</p> -<p>The process is actually quite simple. First, let&rsquo;s define our source pipeline:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># source-pipeline</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: <span style="color:#ae81ff">echo Hello, world!</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a one-line script&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo Add other tasks to build, test, and deploy your project. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo See https://aka.ms/yaml</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a multi-line script&#39;</span> -</span></span></code></pre></div><p>Nothing fancy here, just the build in template pipeline that Microsoft gives us for free when we create a &ldquo;Starter Pipeline&rdquo;.</p> -<p>Now, let&rsquo;s create another pipeline in the same repo that will be triggered when the pipeline above completes:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># dependent-pipeline</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">none</span> <span style="color:#75715e"># we want this pipeline to be triggered manually, not based on PR, etc.</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">pipelines</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">pipeline</span>: <span style="color:#ae81ff">source-pipeline</span> <span style="color:#75715e">#this can be anything</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">source</span>: <span style="color:#e6db74">&#39;source-pipeline&#39;</span> <span style="color:#75715e">#this needs to be the name of the &#39;source&#39; pipeline</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">trigger</span>: <span style="color:#66d9ef">true</span> <span style="color:#75715e"># Run dependent-pipeline pipeline when any run of security-lib-ci completes</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: <span style="color:#ae81ff">echo Hello, world!</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a one-line script&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo Add other tasks to build, test, and deploy your project. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo See https://aka.ms/yaml</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a multi-line script&#39;</span> -</span></span></code></pre></div><p>The resources block above defines our dependency. You want to be sure to configure the trigger of the dependent pipeline appropriately as well.</p> -<p>There are several options for fine-tuning this process. See the office Microsoft documentation below:</p> -<p><a href="https://learn.microsoft.com/en-us/azure/devops/pipelines/process/pipeline-triggers?view=azure-devops">Link to the Microsoft Docs</a></p> - + http://localhost:1313/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ + In this article, we&rsquo;ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to figure this out. Our two pipelines will exist in the same repository. - Update Azure Devops SPN Secret - https://rnemeth90.github.io/posts/2022-09-12-update-azure-devops-spn-secret/ + http://localhost:1313/posts/2022-09-12-update-azure-devops-spn-secret/ Mon, 12 Sep 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-09-12-update-azure-devops-spn-secret/ - <p>If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal.</p> -<p>In this article, I&rsquo;ll show you two methods for updating a secret for a service principal prior to expiration.</p> -<h1 id="update-the-secret-via-the-azure-devops-portal" >Update the secret via the Azure Devops Portal: -<span> - <a href="#update-the-secret-via-the-azure-devops-portal"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h1><ul> -<li>Go to &ldquo;Service Connections&rdquo; in the Azure Devops portal</li> -<li>Find the SPN you want to update, then click &ldquo;Manage Service Principal&rdquo;</li> -<li>Then on the service principal page, click Certificates &amp; Secrets</li> -<li>Create a &ldquo;New Client Secret&rdquo;, take note of the value</li> -<li>Delete the &lsquo;old&rsquo; secret</li> -<li>Return to the Service Connection in the Azure Devops portal</li> -<li>Click Edit - click the verify button. It should tell you the client certificate has expired</li> -<li>Now you need to make an arbitrary change and save it. I just type a character in the optional description and save.</li> -<li>Now edit again and click verify, it will now pick up the new client secret and all is happy.</li> -<li>You can now remove whatever you added to the description.</li> -</ul> - + http://localhost:1313/posts/2022-09-12-update-azure-devops-spn-secret/ + If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal. In this article, I&rsquo;ll show you two methods for updating a secret for a service principal prior to expiration. Update the secret via the Azure Devops Portal: Link to heading Go to &ldquo;Service Connections&rdquo; in the Azure Devops portal Find the SPN you want to update, then click &ldquo;Manage Service Principal&rdquo; Then on the service principal page, click Certificates &amp; Secrets Create a &ldquo;New Client Secret&rdquo;, take note of the value Delete the &lsquo;old&rsquo; secret Return to the Service Connection in the Azure Devops portal Click Edit - click the verify button. - Running Docker in WSL v1 - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ Sun, 26 Jun 2022 15:00:28 +0000 - - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ - <p>I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate.</p> -<p>Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. I receive this nice message:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ docker -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>The command <span style="color:#e6db74">&#39;docker&#39;</span> could not be found in this WSL <span style="color:#ae81ff">1</span> distro. -</span></span><span style="display:flex;"><span>We recommend to convert this distro to WSL <span style="color:#ae81ff">2</span> and activate -</span></span><span style="display:flex;"><span>the WSL integration in Docker Desktop settings. -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>See https://docs.docker.com/docker-for-windows/wsl/ <span style="color:#66d9ef">for</span> details. -</span></span></code></pre></div><p>So I’m in somewhat of a catch-22 here…</p> -<p>To work around this problem until a proper solution is found, I was able to get Docker working with WSL v1.</p> -<p>If you happen to be having a similar issue (and it seems like quite a few people are, considering the number of Github posts I found), just follow these steps:</p> -<ul> -<li>Expose the Docker daemon in docker desktop settings:</li> -</ul> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/02/image-10-1024x585.png"></a></p> -<p>Install the stand-alone Docker client in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ tar zxvf docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ cd docker -</span></span></code></pre></div><p>Set the default Docker daemon in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>export DOCKER_HOST<span style="color:#f92672">=</span>tcp://localhost:2375 -</span></span></code></pre></div><p>Verify you can connect to Docker running on Windows from within WSL:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>./docker info -</span></span></code></pre></div><p>This is also beneficial in that you only have one Docker host to manage your containers, network, etc., rather than two.</p> - + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ + I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. - Accessing Secrets Securely in Azure DevOps Pipelines - https://rnemeth90.github.io/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ + http://localhost:1313/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ Sat, 19 Feb 2022 16:02:50 +0000 - - https://rnemeth90.github.io/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ - <p>This post will cover a secure method for accessing secrets in Azure DevOps pipelines.</p> -<h2 id="why-azure-key-vault" >Why Azure Key Vault? -<span> - <a href="#why-azure-key-vault"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Azure Key Vault is an Azure cloud service used to securely store secrets, keys, and certificates. A secret can be any string of characters, such as API keys, passwords, URLs, etc. Azure Key Vault encrypts data at rest and in transit using HTTPS. Depending on the type of Key Vault you are using, data at rest is encrypted using software encryption (AES 256) or HSM-backed keys.</p> -<p>Azure Key Vault also gives us the ability to control access to secrets, keys, and certificates using native Key Vault access policies or the newer option of Azure IAM (RBAC) integration.</p> -<h2 id="what-are-variable-groups" >What are Variable Groups? -<span> - <a href="#what-are-variable-groups"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>It’s all in the name. Variable groups are simply a method of grouping Azure DevOps pipeline variables. If you created a release for an application named MyAwesomeApp, you could create a variable group named myawesomeapp-var-group that could then store all of the variables you reference in the release. It’s simply a method of organizing variables.</p> -<p>You apply permissions to variable groups so that only certain people and pipelines/releases are able to use them.</p> -<p>You can read more here about variable groups and their usage:</p> -<p><a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/library/variable-groups?view=azure-devops&amp;tabs=yaml#use-a-variable-group">https://docs.microsoft.com/en-us/azure/devops/pipelines/library/variable-groups?view=azure-devops&amp;tabs=yaml#use-a-variable-group</a></p> -<h2 id="creating-a-key-vault-and-adding-secrets" >Creating a Key Vault and Adding Secrets -<span> - <a href="#creating-a-key-vault-and-adding-secrets"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p><strong>If you already have a Key Vault, skip this section.</strong></p> -<p>In this post, we will create a Key Vault using the AzureCLI. To create the Vault and a secret, run these commands:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># Create a resource group</span> -</span></span><span style="display:flex;"><span>az group create --location &lt;location&gt; --name &lt;resource-group-name&gt; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Create a KeyVault</span> -</span></span><span style="display:flex;"><span>az keyvault create --name &lt;keyvault-name&gt; --resource-group &lt;resource-group-name&gt; --enable-soft-delete -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Create some secrets in the Key Vault</span> -</span></span><span style="display:flex;"><span>az keyvault secret set --name username --vault-name &lt;keyvault-name&gt; --value &lt;username&gt; -</span></span><span style="display:flex;"><span>az keyvault secret set --name password --vault-name &lt;keyvault-name&gt; --value &lt;password&gt; -</span></span><span style="display:flex;"><span>az keyvault secret set --name tenantId--vault-name &lt;keyvault-name&gt; --value &lt;tenant id&gt; -</span></span></code></pre></div><p>You will need to update the location and resource group name with whatever values you want. You will also need to update the username, password, and your Azure AD tenant ID. The username you choose will need read access to your subscription.</p> -<h2 id="creating-a-variable-group" >Creating a Variable Group -<span> - <a href="#creating-a-variable-group"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Now we’ll create the variable group in Azure DevOps.</p> -<p>Go to your Azure DevOps project &gt; Pipelines &gt; Library and click “+ Variable Group”:</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image.png"></a></p> -<p>Give your variable group a name. Then toggle the switch “Link secrets from an Azure key vault as variables”. Select your Azure Subscription (you may need to authorize DevOps access to the subscription, and then select the Key Vault.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-1.png"></a></p> -<p>Now we can add the secrets from the Key Vault to the variable group. Under “Variables”, click the “+ Add” button. Select the checkbox next to any secrets you want to add to the variable group, and then click “Ok”.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-7.png"></a></p> -<p>Finally, click the “Save” button. You now have a variable group with secrets linked to a Key Vault. Notice the name of the secret is the only thing visible from the variable group. If you were to update the secret value in the Key Vault, Azure DevOps would automatically pick up the new value.</p> -<h2 id="use-the-variable-group-in-a-pipeline" >Use the Variable Group in a Pipeline -<span> - <a href="#use-the-variable-group-in-a-pipeline"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Now that we have our variable group in place, let’s use it in a pipeline. In Azure DevOps, go to Pipelines and click “New pipeline”.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-8-1024x596.png"></a></p> -<p>Choose “Azure Repos Git” &gt; “&lt; your git repo&gt; “, “Starter Pipeline”, and then paste in the following code (You will need to update the ‘azureSubscription’ field with your SPN):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">variables</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">group</span>: <span style="color:#ae81ff">kv-secrets</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pr</span>: <span style="color:#ae81ff">none</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">stages</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">stage</span>: <span style="color:#ae81ff">print_resource_groups</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">jobs</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">job</span>: <span style="color:#ae81ff">print_resource_groups</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">continueOnError</span>: <span style="color:#66d9ef">false</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">task</span>: <span style="color:#ae81ff">AzureCLI@2</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">inputs</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">azureSubscription</span>: <span style="color:#e6db74">&#39;&lt;Your SPN&gt;&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">scriptType</span>: <span style="color:#e6db74">&#39;bash&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">scriptLocation</span>: <span style="color:#e6db74">&#39;inlineScript&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">inlineScript</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az login --service-principal --username $(username) --password $(password) --tenant $(tenantId) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az group list</span> -</span></span></code></pre></div><p>Now click “Save and Run”, and then “Save and Run” again.</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/02/image-9-1024x596.png"></a></p> -<p>Once the pipeline finishes running, you can see that it was able to read the subscription and create a list of all resource groups found.</p> -<p>This is a simple example of using Key Vault credentials in a pipeline. But you can imagine how useful this could be in more complex scenarios.</p> -<p>That’s all for now. If you have any questions, feel free to reach out!</p> - + http://localhost:1313/posts/2022-02-19-accessing-secrets-ecurely-in-azure-devops-pipelines/ + This post will cover a secure method for accessing secrets in Azure DevOps pipelines. Why Azure Key Vault? Link to heading Azure Key Vault is an Azure cloud service used to securely store secrets, keys, and certificates. A secret can be any string of characters, such as API keys, passwords, URLs, etc. Azure Key Vault encrypts data at rest and in transit using HTTPS. Depending on the type of Key Vault you are using, data at rest is encrypted using software encryption (AES 256) or HSM-backed keys. - Kubernetes Pod Eviction - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ Sat, 05 Feb 2022 23:49:16 +0000 - - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ - <p>In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation.</p> -<h2 id="what-is-pod-eviction" >What is Pod Eviction? -<span> - <a href="#what-is-pod-eviction"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. The most common of which is resource starvation on a node. This is referred to as “node-pressure eviction.”</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>NAME READY STATUS RESTARTS AGE -</span></span><span style="display:flex;"><span>nginx 0/1 Evicted <span style="color:#ae81ff">0</span> 10s -</span></span></code></pre></div><h2 id="eviction-process" >Eviction Process -<span> - <a href="#eviction-process"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The kubelet process running on the node monitors resources such as CPU, memory, disk space, inodes, etc. When one of these resources reaches a certain consumption level, the kubelet will first attempt to clean up resources by deleting non-running pods and images (in the case of storage starvation). The kubelet will then fail one or more pods on the node to reclaim resources. The class of the pod determines the order in which it does this.</p> -<p><strong>Pod Classes</strong></p> -<ul> -<li>Guaranteed: Pods that have requests and limits configured for both CPU and memory</li> -<li>Burstable: Pods with a resource request configured for memory or CPU</li> -<li>Best Effort: Pods without any requests or limits</li> -</ul> -<p>The kubelet will first evict any “best-effort” pods. If this is not enough, the kubelet will evict any “burstable” pods. Pods within the “guaranteed” class are theoretically safe from eviction.</p> -<p>During a node-pressure eviction, the kubelet sets the PodPhase for the selected pods to “Failed.” This causes the pods to terminate. If a daemonSet or replicaSet manages the pod, the Kubernetes controller-manager will create new pods on another node.</p> -<h2 id="recovery" >Recovery -<span> - <a href="#recovery"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Node-pressure eviction is almost always avoidable. We can prevent this type of issue by ensuring that we properly size our clusters and create resource limits for pods.</p> -<p><strong>Resource</strong> <strong>Requests and Limits:</strong></p> -<ul> -<li>Requests: The minimum amount of resources (CPU/memory) that a container needs to start.</li> -<li>Limits: The maximum amount of resources that a container is allowed to use.</li> -</ul> -<p>Pod resources and requests can be defined in a pod spec or deployment spec. Below is an example of a pod spec with resource requests and limits defined:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">frontend</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">nginx</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;64Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;250m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">limits</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;128Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;500m&#34;</span> -</span></span></code></pre></div><p>You will often need to clean up evicted pods manually. If you find that your cluster has a large amount of evicted pods, you can clean them up with the following kubectl commands:</p> -<p><strong>To see all failed pods in the cluster:</strong></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl get pod --all-namespaces --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Failed -</span></span></code></pre></div><p><strong>To remove all failed pods in the cluster:</strong></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl delete pod --all-namespaces --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Failed -</span></span></code></pre></div><p>I hope this article has been helpful. Please reach out if you have any questions or comments! Also, if you would like to learn more, take a look at the official Kubernetes docs:</p> -<p><a href="https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/">https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/</a></p> - + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ + In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation. What is Pod Eviction? Link to heading Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. - Continuous Deployment Models - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ + http://localhost:1313/posts/2022-01-14-continuous-deployment-models/ Fri, 14 Jan 2022 19:24:01 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ - <p>When deploying new software releases to servers or (insert -as-a-service&gt; here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments.</p> -<h2 id="bluegreen-deployments" >Blue/Green Deployments -<span> - <a href="#bluegreen-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. Instead, it gets deployed to another set of servers (blue) first. Since the blue servers are not currently serving any traffic for users, the deployment has no impact. However, once the deployment has been completed successfully and tested, users will be directed to the new deployment (blue). You can control all user traffic or a subset of user traffic if your load balancer supports it (referred to as ‘Progressive Exposure’).</p> -<p>The next release will then repeat the same process. Blue would be the current production environment, so you would first deploy to the green servers. This model requires two sets of identical hosts and a load balancer or reverse proxy in front of them. If there are any unexpected issues with the new release, it is straightforward to switch back to the previous release. The disadvantage to this type of model is that it requires having redundant environments (and potentially wasted resources). However, this is less of a concern if using container orchestration platforms such as Kubernetes.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/01/2022-01-19_07h57_58-1024x575.png" alt="Blue Green deployment model"></p> -<h2 id="immutable-servers" >Immutable Servers -<span> - <a href="#immutable-servers"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>There is an alternative method of blue/green deployments called “immutable servers”. This method is identical to blue/green deployments as described above. However, after switching user traffic over to the servers with the new release, the old servers are destroyed. They are not used again. This type of model becomes particularly efficient when using a pipeline that is capable of creating servers for you (i.e., Azure DevOps Pipelines)</p> -<h2 id="canary-deployments" >Canary Deployments -<span> - <a href="#canary-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>In a canary deployment, not all users are routed to the new release immediately. Only a limited percentage of users get access to the new release. These users are the canaries. They should be monitored closely, so it is important to be using Not all users are routed to the new release immediately in a canary deployment. Only a limited percentage of users get access to the latest release. These users are the canaries.</p> -<p>Organizations should monitor the canaries closely, so it is essential to be using monitoring software capable of looking at the statistics of a web application from the users’ perspective (for example, Application Insights). The number of canaries can increase until all traffic is directed to the new release over time. The most significant advantage of this method is limited exposure to issues. If a problem appears after the release is deployed, only a small subset of users will experience it. After you fix the issues and redeploy the release, it’s best to select a different group of users to be canaries.</p> -<h2 id="ring-based-deployments" >Ring Based Deployments -<span> - <a href="#ring-based-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>A ring-based deployment has multiple production environments. Each serves a limited number of users, similar to a canary deployment. However, you can have as many production environments as you want with a ring-based deployment. New releases are deployed to the rings one by one over time.</p> -<h2 id="feature-flag-deployments" >Feature Flag Deployments -<span> - <a href="#feature-flag-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Feature flags are used to expose new features to sets of users slowly. Unlike the other deployment models, they are not implemented in the infrastructure. Instead, they are typically implemented and enabled in code or database. An example would be a feature flag in a database that gives users access to a button on your web page. A developer could enable the flag for a set of users. These users would be able to see the button; other users would not. Feature flags can even toggle bug fixes or performance improvements.</p> -<p>I will cover implementing blue/green deployments in Azure using Azure DevOps and App Services in a future article.</p> - + http://localhost:1313/posts/2022-01-14-continuous-deployment-models/ + When deploying new software releases to servers or (insert -as-a-service&gt; here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments. Blue/Green Deployments Link to heading Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. - Deploy Azure VMs Using Azure Devops CI/CD Pipeline - https://rnemeth90.github.io/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ + http://localhost:1313/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ Fri, 14 Jan 2022 18:46:35 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ - <p>This article assumes that you have already created a pipeline in Azure Devops and have it linked to an Azure Devops repo. You will need to create a variable named $vmpassword and assign it the value stored in your key vault.</p> -<p>To create a release pipeline that will automatically create a VM (using the password stored in key vault for the local administrator account), do the following:</p> -<ol> -<li>Create a new release pipeline</li> -</ol> -<p><img src="https://www.rnemeth90.github.io/content/images/2021/01/image-13.png" alt=""></p> -<p>3. In the “select a template” box, choose “Empty Job”<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-14.png" alt=""></p> -<p>4. Select “Tasks” in the navigation bar, and then select the appropriate stage. For simplicities sake, we will be using 1 stage within this release.<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-15.png" alt=""></p> -<p>5. Click on the “+” in the Agent job bar, and then in the “Add tasks” section, type in “Key Vault”. Click “Azure Key Vault” and then click “Add”. <img src="https://www.rnemeth90.github.io/content/images/2021/01/image-16.png" alt=""></p> -<p>6. Click on the “Azure Key Vault:” task to configure it. Select your subscription, Key Vault, and the secrets filter. You can also create the $vmpassword variable as a variable within your devops project, rather than assigning it as a secret filter for the release. <img src="https://www.rnemeth90.github.io/content/images/2021/01/image-20.png" alt=""></p> -<p>7. In your Key Vault, you need to grant the devops account access to the Key Vault. To do this, go to your Key Vault and create a new access policy. This policy will be assigned to a service principal that is being used by your Azure Devops project. To find the ID of this service principal, go to your project settings, and under “Pipelines”, click on “Service Connections”. Then select the service connection that resembles your subscription. After doing this, click “Manage Service Principal”. In the service principal window, click “Manifest” and then find the “name” tag within the JSON.<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-19.png" alt=""></p> -<p>8. Now go back to your key vault, and assign an access policy for this service principal. Grant the principal read and list for secrets.</p> -<p>9. Add another agent job for the task (see step 6) and search for “azure cli”. Click on “Add” for Azure CLI. Configure the settings for this job as below:<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-18.png" alt=""></p> -<p>10. Save and run your pipeline. Give it some time to complete, and go take a look at your newly created VM. This is just a very simple example of creating a server as part of a CI/CD pipeline. You can then deploy your code to it, run some tests, destroy them VM, etc. Completely automated.<img src="https://www.rnemeth90.github.io/content/images/2021/01/image-21.png" alt=""></p> - + http://localhost:1313/posts/2022-01-14-deploy-azure-vms-using-azure-devops-ci-cd-pipeline/ + This article assumes that you have already created a pipeline in Azure Devops and have it linked to an Azure Devops repo. You will need to create a variable named $vmpassword and assign it the value stored in your key vault. To create a release pipeline that will automatically create a VM (using the password stored in key vault for the local administrator account), do the following: Create a new release pipeline 3. - Azure Devops &#8211; Self Hosted Agent Service Won&#8217;t Start &#8211; Incorrect Function - https://rnemeth90.github.io/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ + http://localhost:1313/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ Fri, 14 Jan 2022 18:45:00 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ - <p>I setup a self hosted agent for Azure Devops this morning on Server 2012 R2 (legacy Visual Studio dependencies…) and found that I was unable to start the service. The error I received was “Error 1 Incorrect Function” when attempting to start the service in services.msc.</p> -<p>I was attempting to run the agent from within my user profile downloads folder. I originally was not aware the service would be running from this directory. I thought it would copy its binary files to program files directory or programdata, like 99% of all other apps. The service installs and attempts to run itself as the “network service” authority. This account does not have permission to a user profile folder by default, and the installation script is not able to grant it permission for some reason (I didn’t investigate this further). I removed the agent, moved the installation files to the root of c:, and then reinstalled. The agent service is now able to start successfully.</p> - + http://localhost:1313/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ + I setup a self hosted agent for Azure Devops this morning on Server 2012 R2 (legacy Visual Studio dependencies…) and found that I was unable to start the service. The error I received was “Error 1 Incorrect Function” when attempting to start the service in services.msc. I was attempting to run the agent from within my user profile downloads folder. I originally was not aware the service would be running from this directory. - diff --git a/public/tags/devops/page/1/index.html b/public/tags/devops/page/1/index.html index cc2d2885..a3ee3df4 100644 --- a/public/tags/devops/page/1/index.html +++ b/public/tags/devops/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/devops/ - + http://localhost:1313/tags/devops/ + - + diff --git a/public/tags/devops/page/2/index.html b/public/tags/devops/page/2/index.html index 6f11e532..707a3388 100644 --- a/public/tags/devops/page/2/index.html +++ b/public/tags/devops/page/2/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Devops · GeekyRyan + - - -devops - GeekyRyan - - - - - - + - - - - - + + + - - - + + + + + + + + + - - - - - - - - - + + + + - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,299 +79,192 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - + - -
    -
    - -

    Tag: devops

    - +
      + +
    • «
    • -
      -
      -
      -

      Azure Devops &#8211; Self Hosted Agent Service Won&#8217;t Start &#8211; Incorrect Function

      -
      - -
      - + + + -
      - I setup a self hosted agent for Azure Devops this morning on Server 2012 R2 (legacy Visual Studio dependencies…) and found that I was unable to start the service. The error I received was “Error 1 Incorrect Function” when attempting to start the service in services.msc. -I was attempting to run the agent from within my user profile downloads folder. I originally was not aware the service would be running from this directory. -
      + -
      - Read more -
      + +
    • 1
    • + + - - - -
    - https://rnemeth90.github.io/posts/2022-01-14-azure-devops-self-hosted-agent-service-wont-start-incorrect-function/ - Ryan + + -
    - - - - - -
    -
    - +
    +
    + © + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - +
    +
    + + + + + + - - -
    - - + - + -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/tags/dhcp/index.html b/public/tags/dhcp/index.html index 3f0e33bd..9f4ff292 100644 --- a/public/tags/dhcp/index.html +++ b/public/tags/dhcp/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: DHCP · GeekyRyan + - - -DHCP - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,281 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - + - - -
    -
    - -

    Tag: DHCP

    - - - -
    - https://rnemeth90.github.io/posts/2014-12-08-dhcp-address-negotiation-process/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/dhcp/index.xml b/public/tags/dhcp/index.xml index c82fd327..86196cc5 100644 --- a/public/tags/dhcp/index.xml +++ b/public/tags/dhcp/index.xml @@ -2,24 +2,18 @@ DHCP on GeekyRyan - https://rnemeth90.github.io/tags/dhcp/ - GeekyRyan (DHCP) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/dhcp/ + Recent content in DHCP on GeekyRyan + Hugo + en Mon, 08 Dec 2014 03:08:00 +0000 - - - - + DHCP Address Negotiation Process - https://rnemeth90.github.io/posts/2014-12-08-dhcp-address-negotiation-process/ + http://localhost:1313/posts/2014-12-08-dhcp-address-negotiation-process/ Mon, 08 Dec 2014 03:08:00 +0000 - - https://rnemeth90.github.io/posts/2014-12-08-dhcp-address-negotiation-process/ - <p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/12/2014-12-07_22h07_33.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/12/2014-12-07_22h07_33.png" alt=""></a></p> - + http://localhost:1313/posts/2014-12-08-dhcp-address-negotiation-process/ + - diff --git a/public/tags/dhcp/page/1/index.html b/public/tags/dhcp/page/1/index.html index d6534b16..6b1f21be 100644 --- a/public/tags/dhcp/page/1/index.html +++ b/public/tags/dhcp/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/dhcp/ - + http://localhost:1313/tags/dhcp/ + - + diff --git a/public/tags/dirsync/index.html b/public/tags/dirsync/index.html index a7f3e42d..a6bbf8ca 100644 --- a/public/tags/dirsync/index.html +++ b/public/tags/dirsync/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: DirSync · GeekyRyan + - - -DirSync - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,295 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Tag: DirSync

    - - - -
    -
    -
    -

    Azure AD Connect No-Start-Connection

    -
    -
    +
    +
    + © -
    - This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working. -After forcing the sync, I opened miisclient and noticed some strange errors. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2018-07-26-azure-ad-connect-no-start-connection/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/dirsync/index.xml b/public/tags/dirsync/index.xml index 3140bbb0..92d40521 100644 --- a/public/tags/dirsync/index.xml +++ b/public/tags/dirsync/index.xml @@ -2,29 +2,18 @@ DirSync on GeekyRyan - https://rnemeth90.github.io/tags/dirsync/ - GeekyRyan (DirSync) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/dirsync/ + Recent content in DirSync on GeekyRyan + Hugo + en Thu, 26 Jul 2018 12:22:00 +0000 - - - - + Azure AD Connect No-Start-Connection - https://rnemeth90.github.io/posts/2018-07-26-azure-ad-connect-no-start-connection/ + http://localhost:1313/posts/2018-07-26-azure-ad-connect-no-start-connection/ Thu, 26 Jul 2018 12:22:00 +0000 - - https://rnemeth90.github.io/posts/2018-07-26-azure-ad-connect-no-start-connection/ - <p>This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working.</p> -<p>After forcing the sync, I opened miisclient and noticed some strange errors. We sync multiple on-prem AD forests to Azure AD, and the status for one of them was “no-start-connection”. That error in itself does not seem significant to me. However, after clicking on the “failed-connection” link in the Connection Status pane, things became much more clear.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_05.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_05.png" alt=""></a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_18.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_18.png" alt=""></a></p> -<p>The domain controllers for the forest in question are in a datacenter that is geographically separated from the datacenter that our Azure AD Sync server lives in. The two sites are connected via a S2S VPN.</p> -<p>There was obviously some type of connection issue between our two datacenters. In my case, the issue was transient, and resolved itself after a few minutes. But if you’re experiencing this error message, check your L2/L3 connection. Also, verify DNS is working and someone didn’t make changes to your firewall(s). Just walk up or down the OSI model and you’ll eventually find the problem.</p> - + http://localhost:1313/posts/2018-07-26-azure-ad-connect-no-start-connection/ + This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working. After forcing the sync, I opened miisclient and noticed some strange errors. - diff --git a/public/tags/dirsync/page/1/index.html b/public/tags/dirsync/page/1/index.html index b83e5d79..2e303571 100644 --- a/public/tags/dirsync/page/1/index.html +++ b/public/tags/dirsync/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/dirsync/ - + http://localhost:1313/tags/dirsync/ + - + diff --git a/public/tags/docker/index.html b/public/tags/docker/index.html index 6ba6d410..96bc04a4 100644 --- a/public/tags/docker/index.html +++ b/public/tags/docker/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Docker · GeekyRyan + - - -Docker - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,307 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Tag: Docker

    - - - -
    -
    -
    -

    Running Docker in WSL v1

    -
    -
    +
    +
    + © -
    - I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. -Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/docker/index.xml b/public/tags/docker/index.xml index 108859fa..20cbc5b9 100644 --- a/public/tags/docker/index.xml +++ b/public/tags/docker/index.xml @@ -2,48 +2,18 @@ Docker on GeekyRyan - https://rnemeth90.github.io/tags/docker/ - GeekyRyan (Docker) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/docker/ + Recent content in Docker on GeekyRyan + Hugo + en Sun, 26 Jun 2022 15:00:28 +0000 - - - - + Running Docker in WSL v1 - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ Sun, 26 Jun 2022 15:00:28 +0000 - - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ - <p>I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate.</p> -<p>Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. I receive this nice message:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ docker -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>The command <span style="color:#e6db74">&#39;docker&#39;</span> could not be found in this WSL <span style="color:#ae81ff">1</span> distro. -</span></span><span style="display:flex;"><span>We recommend to convert this distro to WSL <span style="color:#ae81ff">2</span> and activate -</span></span><span style="display:flex;"><span>the WSL integration in Docker Desktop settings. -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>See https://docs.docker.com/docker-for-windows/wsl/ <span style="color:#66d9ef">for</span> details. -</span></span></code></pre></div><p>So I’m in somewhat of a catch-22 here…</p> -<p>To work around this problem until a proper solution is found, I was able to get Docker working with WSL v1.</p> -<p>If you happen to be having a similar issue (and it seems like quite a few people are, considering the number of Github posts I found), just follow these steps:</p> -<ul> -<li>Expose the Docker daemon in docker desktop settings:</li> -</ul> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/02/image-10-1024x585.png"></a></p> -<p>Install the stand-alone Docker client in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ tar zxvf docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ cd docker -</span></span></code></pre></div><p>Set the default Docker daemon in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>export DOCKER_HOST<span style="color:#f92672">=</span>tcp://localhost:2375 -</span></span></code></pre></div><p>Verify you can connect to Docker running on Windows from within WSL:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>./docker info -</span></span></code></pre></div><p>This is also beneficial in that you only have one Docker host to manage your containers, network, etc., rather than two.</p> - + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ + I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. - diff --git a/public/tags/docker/page/1/index.html b/public/tags/docker/page/1/index.html index 4ff4604d..d57ae36c 100644 --- a/public/tags/docker/page/1/index.html +++ b/public/tags/docker/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/docker/ - + http://localhost:1313/tags/docker/ + - + diff --git a/public/tags/dotnet/index.html b/public/tags/dotnet/index.html index bf86a541..f264bf1e 100644 --- a/public/tags/dotnet/index.html +++ b/public/tags/dotnet/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Dotnet · GeekyRyan + - - -dotnet - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,303 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Tag: dotnet

    - - - -
    -
    -
    -

    Handling Graceful Shutdown in a .NET App Hosted in Kubernetes

    -
    -
    +
    +
    + © -
    - I was recently involved with troubleshooting some API’s hosted in Kubernetes throwing http/502’s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/dotnet/index.xml b/public/tags/dotnet/index.xml index 0bb9271d..e564c47b 100644 --- a/public/tags/dotnet/index.xml +++ b/public/tags/dotnet/index.xml @@ -1,138 +1,19 @@ - dotnet on GeekyRyan - https://rnemeth90.github.io/tags/dotnet/ - GeekyRyan (dotnet) - Hugo -- gohugo.io - en-us + Dotnet on GeekyRyan + http://localhost:1313/tags/dotnet/ + Recent content in Dotnet on GeekyRyan + Hugo + en Wed, 28 Dec 2022 00:00:00 +0000 - - - - + Handling Graceful Shutdown in a .NET App Hosted in Kubernetes - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ Wed, 28 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ - <p>I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. It was actually a combination of these blogs (and the resolutions posted) that ended up resolving our issue.</p> -<h3 id="so-what-was-actually-causing-the-502s" >So what was actually causing the 502&rsquo;s? -<span> - <a href="#so-what-was-actually-causing-the-502s"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h3><p>As stated, these APIs are hosted in Kubernetes. They are written primarily in c# (.NET Framework) and hosted in Windows Server Core containers. The pods are load balanced using a service, and we have an Nginx ingress on top of the service. Nothing fancy, just a typical setup that you may have seen or even built yourself. We implement automatic scaling for our replica sets using a standard Kubernetes-native HPA or Keda, depending on the app. We have autoscale rules defined for the pods. Our clusters are hosted in Azure Kubernetes Service, and we autoscale our node pools. So, there are several layers of scaling happening in our clusters at any given time. Occasionally, when a pod was handling a client request, Kubelet or a controller would come along and scale the pod in. We were initially under the belief that the <code>terminationGracePeriodSeconds</code> value within our deployment would allow the pod to continue running for the defined number of seconds. However, we were mistaken. This value tells Kubernetes to allow the application running within the pod some time to clean up. It does <em>not</em> tell the app to continue running for the defined number of seconds after it receives a sigterm signal. This logic actually needs to be implemented within the application itself, or with a prestop hook. The prestop method is <a href="https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/">well documented</a>, so I will not cover it here.</p> -<p>To implement this in a .NET Framework app running in Windows, you need to add this registry key to your container.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">RUN</span> reg add hklm<span style="color:#ae81ff">\s</span>ystem<span style="color:#ae81ff">\c</span>urrentcontrolset<span style="color:#ae81ff">\c</span>ontrol /v WaitToKillServiceTimeout /t REG_SZ /d <span style="color:#ae81ff">60000</span> /f<span style="color:#960050;background-color:#1e0010"> -</span></span></span></code></pre></div><p>This value tells Windows to wait a number of milliseconds before shutting down Normally, Windows only waits for 5 seconds (default) before shutting down any &lsquo;background&rsquo; processes. Windows forcibly shuts down processes after this period of time.</p> -<p>Next, in the startup class, we&rsquo;ll add the following code. I have added inline comments to explain.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c#" data-lang="c#"><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">namespace</span> MyApp.APIConsoleHost -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Program</span> -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Register the SetConsoleCtrlHandler function in kernel32.dll in the -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> application to capture CTRL_SHUTDOWN_EVENT events for resource reclamation -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e"> [DllImport(&#34;Kernel32&#34;)]</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">extern</span> <span style="color:#66d9ef">bool</span> SetConsoleCtrlHandler(HandlerRoutine handler, <span style="color:#66d9ef">bool</span> <span style="color:#66d9ef">add</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Define a delegate for our handler routine</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">delegate</span> <span style="color:#66d9ef">bool</span> HandlerRoutine(CtrlTypes ctrlType); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">volatile</span> ManualResetEvent _exitEvent = <span style="color:#66d9ef">new</span> ManualResetEvent(<span style="color:#66d9ef">false</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> HandlerRoutine _handler; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Define the event types that we want to handle when the application receives a SIGTERM -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_C_EVENT = 0, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_BREAK_EVENT = 1, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_CLOSE_EVENT = 2, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_LOGOFF_EVENT = 5, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_SHUTDOWN_EVENT = 6 -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">enum</span> CtrlTypes -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> CTRL_SHUTDOWN_EVENT = <span style="color:#ae81ff">6</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Here we are defining how we want to handle the shutdown -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We get a timeout value from an env variable named APP_SHUTDOWN_TIMEOUT -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> If that env variable is not found, we default to 60 seconds. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We then switch on our CtrlTypes enum and handle each value accordingly, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then return true. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">bool</span> ConsoleCtrlCheck(CtrlTypes ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> timeout = ConfigurationManager.AppSettings[<span style="color:#e6db74">&#34;APP_SHUTDOWN_TIMEOUT&#34;</span>]; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> (<span style="color:#66d9ef">string</span>.IsNullOrEmpty(timeout)) { timeout = <span style="color:#e6db74">&#34;60&#34;</span>; } -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">int</span> counter = <span style="color:#66d9ef">int</span>.Parse(timeout); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">switch</span> (ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> CtrlTypes.CTRL_SHUTDOWN_EVENT: -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] CTRL_SHUTDOWN received&#34;</span>); -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] Web Server is stopping in {counter} seconds&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">while</span> (counter &gt; <span style="color:#ae81ff">0</span>) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> Thread.Sleep(TimeSpan.FromSeconds(<span style="color:#ae81ff">1</span>)); -</span></span><span style="display:flex;"><span> counter--; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.Set(); -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span>; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span>: -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">false</span>; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Our main method is pretty standard. However, we first register a new handler (_handler), -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then pass it to to the SetConsoleCtrlHandler() method we imported from Kernel32.dll. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> The only other &#39;unique&#39; thing is the _exitEvent.WaitOne(); call defined at the bottom of main(). -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> This is necessary so that main does not immediately exit, and wait&#39;s for a signal. We defined a -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> property for this _exitEvent of type ManualResetEvent at the top of this class file. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> Main(<span style="color:#66d9ef">string</span>[] args) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> _handler += <span style="color:#66d9ef">new</span> HandlerRoutine(ConsoleCtrlCheck); -</span></span><span style="display:flex;"><span> SetConsoleCtrlHandler(_handler, <span style="color:#66d9ef">true</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = BuildStartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> WebApp.Start&lt;SelfHostStartup&gt;(startOptions); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">&#34;Press CTRL+C to stop it&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.WaitOne(); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> StartOptions BuildStartOptions() -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = <span style="color:#66d9ef">new</span> StartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted start options</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> startOptions; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>To prevent the HandlerRoutine instance from being recycled by the GC before the program exits, the HandlerRoutine must be static (as seen in the above example). This is important because if the handlerroutine is recycled before the application is finished, it will throw an error, as shown here:</p> -<pre tabindex="0"><code>A callback was made on a garbage collected delegate of type &#39;Program+HandlerRoutine::Invoke&#39;. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called. -</code></pre> + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. - diff --git a/public/tags/dotnet/page/1/index.html b/public/tags/dotnet/page/1/index.html index b1dc6d8f..3e80ff33 100644 --- a/public/tags/dotnet/page/1/index.html +++ b/public/tags/dotnet/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/dotnet/ - + http://localhost:1313/tags/dotnet/ + - + diff --git a/public/tags/ef-core/index.html b/public/tags/ef-core/index.html index 33ab0ac5..c64754a3 100644 --- a/public/tags/ef-core/index.html +++ b/public/tags/ef-core/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Ef Core · GeekyRyan + - - -ef core - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,306 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Tag: ef core

    - - - -
    -
    -
    -

    EF Core &#8211; Unable to create an object of type DbContext

    -
    -
    +
    +
    + © -
    - This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it! -When running EF Core migrations in a solution, you may come across this error: -There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio. -To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/ef-core/index.xml b/public/tags/ef-core/index.xml index b95e5ec5..fb31554c 100644 --- a/public/tags/ef-core/index.xml +++ b/public/tags/ef-core/index.xml @@ -1,32 +1,19 @@ - ef core on GeekyRyan - https://rnemeth90.github.io/tags/ef-core/ - GeekyRyan (ef core) - Hugo -- gohugo.io - en-us + Ef Core on GeekyRyan + http://localhost:1313/tags/ef-core/ + Recent content in Ef Core on GeekyRyan + Hugo + en Sun, 12 Jun 2022 13:58:52 +0000 - - - - + EF Core &#8211; Unable to create an object of type DbContext - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ Sun, 12 Jun 2022 13:58:52 +0000 - - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ - <p>This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it!</p> -<p>When running EF Core migrations in a solution, you may come across this error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-1-1024x142.png"></a></p> -<p>There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio.</p> -<p>To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-2.png"></a></p> -<p>If you are using clean architecture, or some other architecture that has your startup context and your dbContext in different projects, you will need to set your startup project to your runtime, and the ‘Default Project’ in the package manager console to the project containing your dbContext.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-3-1024x493.png"></a></p> - + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it! When running EF Core migrations in a solution, you may come across this error: There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio. To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’. - diff --git a/public/tags/ef-core/page/1/index.html b/public/tags/ef-core/page/1/index.html index e5c07944..74b272bc 100644 --- a/public/tags/ef-core/page/1/index.html +++ b/public/tags/ef-core/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/ef-core/ - + http://localhost:1313/tags/ef-core/ + - + diff --git a/public/tags/entity-framework/index.html b/public/tags/entity-framework/index.html index a87cff2a..ce4c08d0 100644 --- a/public/tags/entity-framework/index.html +++ b/public/tags/entity-framework/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Entity Framework · GeekyRyan + - - -entity framework - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,306 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Tag: entity framework

    - - - -
    -
    -
    -

    EF Core &#8211; Unable to create an object of type DbContext

    -
    -
    +
    +
    + © -
    - This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it! -When running EF Core migrations in a solution, you may come across this error: -There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio. -To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/entity-framework/index.xml b/public/tags/entity-framework/index.xml index 6f97f923..89544f2c 100644 --- a/public/tags/entity-framework/index.xml +++ b/public/tags/entity-framework/index.xml @@ -1,32 +1,19 @@ - entity framework on GeekyRyan - https://rnemeth90.github.io/tags/entity-framework/ - GeekyRyan (entity framework) - Hugo -- gohugo.io - en-us + Entity Framework on GeekyRyan + http://localhost:1313/tags/entity-framework/ + Recent content in Entity Framework on GeekyRyan + Hugo + en Sun, 12 Jun 2022 13:58:52 +0000 - - - - + EF Core &#8211; Unable to create an object of type DbContext - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ Sun, 12 Jun 2022 13:58:52 +0000 - - https://rnemeth90.github.io/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ - <p>This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it!</p> -<p>When running EF Core migrations in a solution, you may come across this error:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-1-1024x142.png"></a></p> -<p>There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio.</p> -<p>To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-2.png"></a></p> -<p>If you are using clean architecture, or some other architecture that has your startup context and your dbContext in different projects, you will need to set your startup project to your runtime, and the ‘Default Project’ in the package manager console to the project containing your dbContext.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/06/image-3-1024x493.png"></a></p> - + http://localhost:1313/posts/2022-06-12-ef-core-unable-to-create-an-object-of-type-dbcontext/ + This problem has bitten me more than once, and I can never remember how to fix it. So, why not write a blog post about it! When running EF Core migrations in a solution, you may come across this error: There are several apparent causes. However, in my case (every time I have seen this), it has been caused by having multiple startup projects selected in Visual Studio. To fix this, simply open your Solution properties and set the startup project to ‘Current Selection’. - diff --git a/public/tags/entity-framework/page/1/index.html b/public/tags/entity-framework/page/1/index.html index a0732025..21317622 100644 --- a/public/tags/entity-framework/page/1/index.html +++ b/public/tags/entity-framework/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/entity-framework/ - + http://localhost:1313/tags/entity-framework/ + - + diff --git a/public/tags/exchange/index.html b/public/tags/exchange/index.html index 713df5b5..ffe691de 100644 --- a/public/tags/exchange/index.html +++ b/public/tags/exchange/index.html @@ -1,750 +1,264 @@ + - - - - - - - + + Tag: Exchange · GeekyRyan + - + -Exchange - GeekyRyan - + + + - - - + + + + + + + + + - - - - + + + + + + + - - - - - - - - - + - + + + - - - - - - - - - - + + + + + + + - - - - + - - - - - - - - - - - - - - - - - - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - - -
    -
    - -

    Tag: Exchange

    - - - -
    -
    -
    -

    Exchange 2016 Hybrid Deploy Check: Username or Password Invalid

    -
    - -
    - - -
    - These days, it seems every Microsoft product comes with its own unique set of head scratchers. Microsoft Exchange Server is no exception to this. I was installing Exchange 2016 earlier today, to be used as a hybrid configuration server for Office 365 (no local mailboxes). I downloaded the self depackaging executable from Microsoft, and attempted to install it. If you currently have a hybrid configuration (which we did, with Exchange 2010), the Exchange 2016 installer will detect this and run some tests to verify that the Office 365 tenant is ready for Exchange 2016 (more info here: https://technet. -
    - - -
    - Read more -
    - - - - - - - - - -
    - - - -
    -
    -
    -

    How to Permanently Remove Office 365 Users

    -
    - -
    - - -
    - After deleting a user in Office 365, their account is moved to a ‘recycle bin’ for 30 days. This allows the user account to be easily recovered. This can often cause issues when attempting to recreate a mailbox while a hybrid configuration is in place. -To permanently delete the user within Office 365, first delete the user in the Office 365 Admin Portal or using Powershell. Then, connect to your Azure Active Directory environment with Powershell using the “Connect-MsolService” cmdlet. -
    - - -
    - Read more -
    - - - - - - - -
    - -
    -
    -
    -

    Access is Denied When Attempting to Delete a Dynamic Distribution Group

    -
    - -
    - - -
    - You may receive the error below when attempting to delete a dynamic distribution group. -To resolve this, open ADUC and show advanced features (Click View > Advanced Features). Then find the object for the dynamic distribution group and open the properties window. Browse to the “Object” tab and uncheck the “Protect object from accidental deletion” box. Wait for ADDS to replicate or force replication yourself. -Go back to the ECP and you should be able to delete the group. -
    - - -
    - Read more -
    - - - - - - -
    - -
    -
    -
    -

    Exchange 2013: Error 0x80070070 While Adding DAG Member

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Tag: Exchange +

    +
    + +
    +
  • + 2015-08-12 + Failed to Mount Exchange 2010 Database +
  • -
    -
    -
    -

    Finding All Mailboxes with a Forwarding Address in Exchange 2003

    -
    - -
    + + - -
    - Believe it or not, the MSP I work for still has a client who is using Exchange 2003 as their primary email service. Despite several attempts at convincing them of the power of Office 365, they refuse to migrate. Last week the CFO contacted me and requested we provide them with a report of all users who have their email forwarded to another mailbox. “Ok, no problem.” I said helpfully as the client informed me of their request (at the time I didn’t even think about them having Exchange 2003…). -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Failed to Mount Exchange 2010 Database

    -
    -
    +
    +
    + © -
    - Recently, one of my users’ came to me and said he was missing two months worth of email. This was just after migrating to Exchange Online. We were using Exchange 2010 with System Center DPM for backups. -I restored the database that the users’ mailbox was on from a backup then copied it over to the Exchange server from the network share I restored it to. All was going well, until I tried to mount the darn thing. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2015-08-12-failed-to-mount-exchange-2010-database/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/exchange/index.xml b/public/tags/exchange/index.xml index 0bcd0de0..a6508df8 100644 --- a/public/tags/exchange/index.xml +++ b/public/tags/exchange/index.xml @@ -2,122 +2,60 @@ Exchange on GeekyRyan - https://rnemeth90.github.io/tags/exchange/ - GeekyRyan (Exchange) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/exchange/ + Recent content in Exchange on GeekyRyan + Hugo + en Tue, 07 Nov 2017 13:30:00 +0000 - - - - + Exchange 2016 Hybrid Deploy Check: Username or Password Invalid - https://rnemeth90.github.io/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ + http://localhost:1313/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ Tue, 07 Nov 2017 13:30:00 +0000 - - https://rnemeth90.github.io/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ - <p>These days, it seems every Microsoft product comes with its own unique set of head scratchers. Microsoft Exchange Server is no exception to this. I was installing Exchange 2016 earlier today, to be used as a hybrid configuration server for Office 365 (no local mailboxes). I downloaded the self depackaging executable from Microsoft, and attempted to install it. If you currently have a hybrid configuration (which we did, with Exchange 2010), the Exchange 2016 installer will detect this and run some tests to verify that the Office 365 tenant is ready for Exchange 2016 (more info here: <a href="https://technet.microsoft.com/en-us/library/ms.exch.setup.hybridconfigurationstatuspage(v=exchg.160).aspx">https://technet.microsoft.com/en-us/library/ms.exch.setup.hybridconfigurationstatuspage(v=exchg.160).aspx</a>). You’ll be prompted for Office 365 credentials (the user must have the Organization Management role). Seems simple enough, right? Wrong.</p> -<p>After typing in the username and <em>pasting</em> the password into the password field, setup came back with an error message stating the username or password was wrong. I then clicked the back button, and it crashed. I ran through this process a few more times, all with the same outcome. I even rebooted the server, which (in my opinion) should never be the resolution to a software problem. I looked through setup logs and found no indication of what the problem could be…</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2017/11/2017-11-07_12h57_08.png" alt=""></p> -<p>It was on the fourth try that I typed in the password, and this seemed to work. I didn’t receive any error messages about the credentials being wrong. The Exchange setup seemed to continue on successfully. However, it then failed with a different error:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2017/11/2017-11-07_13h12_02.png" alt=""></p> -<p>I again looked through the setup logs and found that this error happened anytime setup tried to run the “Get-OrganizationConfig” cmdlet. After troubleshooting for a little while, and no resolution in sight, I turned to Google. One of the posts I came across said that this is a bug in the Exchange installer, and to try and use the Cumulative Update installer instead. Apparently, with Exchange 2016, the Cumulative Update installer’s include all of the Exchange binaries, not just the updated binaries. I downloaded the installer for CU7 (all 6 gigabytes of it…) and successfully installed Exchange 2016. Hope this helps anyone out there struggling with this.</p> - + http://localhost:1313/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ + These days, it seems every Microsoft product comes with its own unique set of head scratchers. Microsoft Exchange Server is no exception to this. I was installing Exchange 2016 earlier today, to be used as a hybrid configuration server for Office 365 (no local mailboxes). I downloaded the self depackaging executable from Microsoft, and attempted to install it. If you currently have a hybrid configuration (which we did, with Exchange 2010), the Exchange 2016 installer will detect this and run some tests to verify that the Office 365 tenant is ready for Exchange 2016 (more info here: https://technet. - New Script: BulkAdd-SpamFilterWhitelist.ps1 - https://rnemeth90.github.io/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ + http://localhost:1313/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ Mon, 26 Jun 2017 22:16:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ - <p>This script is capable of adding a list of domains to an Exchange Online Spam Filter policy. It can be downloaded from TechNet or Github.</p> -<p><a href="https://github.com/rnemeth90/PowerShell/blob/master/BulkAdd-SpamFilterWhitelist.ps1">Github</a></p> -<p><a href="https://gallery.technet.microsoft.com/BulkAdd-SpamFilterWhitelist-2d2b596a">TechNet</a></p> - + http://localhost:1313/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ + This script is capable of adding a list of domains to an Exchange Online Spam Filter policy. It can be downloaded from TechNet or Github. Github TechNet - How to Permanently Remove Office 365 Users - https://rnemeth90.github.io/posts/2017-06-20-how-to-permanently-remove-office-365-users/ + http://localhost:1313/posts/2017-06-20-how-to-permanently-remove-office-365-users/ Tue, 20 Jun 2017 18:13:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-20-how-to-permanently-remove-office-365-users/ - <p>After deleting a user in Office 365, their account is moved to a ‘recycle bin’ for 30 days. This allows the user account to be easily recovered. This can often cause issues when attempting to recreate a mailbox while a hybrid configuration is in place.</p> -<p>To permanently delete the user within Office 365, first delete the user in the Office 365 Admin Portal or using Powershell. Then, connect to your Azure Active Directory environment with Powershell using the “Connect-MsolService” cmdlet.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h06_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h06_20.png" alt=""></a></p> -<p>To see a list of user accounts currently in the recycle bin, run this cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h09_47.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h09_47.png" alt=""></a></p> -<p>Then, to permanently delete all accounts in the recycle bin, run this cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h10_16.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h10_16.png" alt=""></a></p> -<p>To remove a specific user, run this cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h11_15.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h11_15.png" alt=""></a></p> - + http://localhost:1313/posts/2017-06-20-how-to-permanently-remove-office-365-users/ + After deleting a user in Office 365, their account is moved to a ‘recycle bin’ for 30 days. This allows the user account to be easily recovered. This can often cause issues when attempting to recreate a mailbox while a hybrid configuration is in place. To permanently delete the user within Office 365, first delete the user in the Office 365 Admin Portal or using Powershell. Then, connect to your Azure Active Directory environment with Powershell using the “Connect-MsolService” cmdlet. - Access is Denied When Attempting to Delete a Dynamic Distribution Group - https://rnemeth90.github.io/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ + http://localhost:1313/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ Mon, 12 Jun 2017 13:41:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ - <p>You may receive the error below when attempting to delete a dynamic distribution group.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-12_09h29_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-12_09h29_20.png" alt=""></a></p> -<p>To resolve this, open ADUC and show advanced features (Click View &gt; Advanced Features). Then find the object for the dynamic distribution group and open the properties window. Browse to the “Object” tab and uncheck the “Protect object from accidental deletion” box. Wait for ADDS to replicate or force replication yourself.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-12_09h34_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-12_09h34_20.png" alt=""></a></p> -<p>Go back to the ECP and you should be able to delete the group.</p> - + http://localhost:1313/posts/2017-06-12-access-is-denied-when-attempting-to-delete-a-dynamic-distribution-group/ + You may receive the error below when attempting to delete a dynamic distribution group. To resolve this, open ADUC and show advanced features (Click View &gt; Advanced Features). Then find the object for the dynamic distribution group and open the properties window. Browse to the “Object” tab and uncheck the “Protect object from accidental deletion” box. Wait for ADDS to replicate or force replication yourself. Go back to the ECP and you should be able to delete the group. - Exchange 2013: Error 0x80070070 While Adding DAG Member - https://rnemeth90.github.io/posts/2016-10-04-exchange-2013-error-0x80070070-while/ + http://localhost:1313/posts/2016-10-04-exchange-2013-error-0x80070070-while/ Tue, 04 Oct 2016 00:21:00 +0000 - - https://rnemeth90.github.io/posts/2016-10-04-exchange-2013-error-0x80070070-while/ - <p>Error: A server-side database availability group administrative operation failed. Error Failed to add or remove the Failover-Clustering feature. Error: The request to add or remove features on the specified server failed. A DISM session could not be opened. An error occurred accessing the temporary folder C:WindowsTEMP57ACE2DE-4CD2-4F5F-B7A0-93D867A89A12. Ensure that the path to the temporary folder exists and that you have Read/Write permissions on the folder. Error: 0x80070070</p> -<p>Solution: I was attempting to remotely add the DAG member from the ECP on my workstation. I logged into the server and found that the system drive was nearly full (~100MB free). Luckily this mailbox server was a virtual machine, and I was able to quickly expand the drive using VMM. After doing this I was able to successfully add the mailbox server to the DAG.</p> - + http://localhost:1313/posts/2016-10-04-exchange-2013-error-0x80070070-while/ + Error: A server-side database availability group administrative operation failed. Error Failed to add or remove the Failover-Clustering feature. Error: The request to add or remove features on the specified server failed. A DISM session could not be opened. An error occurred accessing the temporary folder C:WindowsTEMP57ACE2DE-4CD2-4F5F-B7A0-93D867A89A12. Ensure that the path to the temporary folder exists and that you have Read/Write permissions on the folder. Error: 0x80070070 Solution: I was attempting to remotely add the DAG member from the ECP on my workstation. - Finding All Mailboxes with a Forwarding Address in Exchange 2003 - https://rnemeth90.github.io/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ + http://localhost:1313/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ Mon, 07 Sep 2015 23:13:00 +0000 - - https://rnemeth90.github.io/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ - <p>Believe it or not, the MSP I work for still has a client who is using Exchange 2003 as their primary email service. Despite several attempts at convincing them of the power of Office 365, they refuse to migrate. Last week the CFO contacted me and requested we provide them with a report of all users who have their email forwarded to another mailbox. “Ok, no problem.” I said helpfully as the client informed me of their request (at the time I didn’t even think about them having Exchange 2003…). I figured I would just connect to their server and do some quick PowerShell magic, and that would be it. Quick and painless, right? Wrong.</p> -<p>I did the RDP dance and got connected to their server, and my jaw just about hit the floor when I couldn’t find the Exchange Management Shell! I asked around the office to see if any of the other guys could help, but no one knew what to do. However, after talking with one of the guys, I remembered that this is Active Directory we are dealing with. There are objects, and those objects have attributes. The mailboxes/user accounts are objects, and those objects have attributes. So what attribute is it that controls forwarding addresses? I manually found one of the users who had a forwarding address configured. Then I opened up Active Directory Users and Computers, opened up her account properties, and went to the Attribute Editor tab. I filtered for attributes that have values and was able to see the email address that her mail was forwarding to. This was the “altRecipient” attribute.</p> -<p>I then did an “Advanced” search in Active Directory Users and Computers for any objects that have the “altRecipient” attribute configured, like so:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/09/ExchangeForwarding.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/09/ExchangeForwarding.png" alt=""></a></p> -<p>This search showed me all of the mailboxes that have an alternate recipient (forwarding address) configured. Not sure if there is another way to obtain this information, but this is the way that worked for me. Hopefully this article is able to help someone in the same situation.</p> - + http://localhost:1313/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ + Believe it or not, the MSP I work for still has a client who is using Exchange 2003 as their primary email service. Despite several attempts at convincing them of the power of Office 365, they refuse to migrate. Last week the CFO contacted me and requested we provide them with a report of all users who have their email forwarded to another mailbox. “Ok, no problem.” I said helpfully as the client informed me of their request (at the time I didn’t even think about them having Exchange 2003…). - Failed to Mount Exchange 2010 Database - https://rnemeth90.github.io/posts/2015-08-12-failed-to-mount-exchange-2010-database/ + http://localhost:1313/posts/2015-08-12-failed-to-mount-exchange-2010-database/ Wed, 12 Aug 2015 12:59:00 +0000 - - https://rnemeth90.github.io/posts/2015-08-12-failed-to-mount-exchange-2010-database/ - <p>Recently, one of my users’ came to me and said he was missing two months worth of email. This was just after migrating to Exchange Online. We were using Exchange 2010 with System Center DPM for backups.</p> -<p>I restored the database that the users’ mailbox was on from a backup then copied it over to the Exchange server from the network share I restored it to. All was going well, until I tried to mount the darn thing.</p> -<p>I was getting this error and could not for the life of me decry-pt the meaning of it. There is obviously some type of IO issue/file not found. But what could it be?</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/1-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/1-1.png" alt=""></a></p> -<p>I figured I’d better kick this one off with some basic troubleshooting. First, I checked the health of the database and made sure it was clean. Passed that test…</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/2-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/2-1.png" alt=""></a></p> -<p>Then ran a repair on the database, to no avail.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/3-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/3-1.png" alt=""></a></p> -<p>After racking my brain for a good thirty minutes, and a few failed Google searches, I found the solution. It was so simple! I created the log file directory in the folder with the database, and voila, the database mounted without a single error!</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/7.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/7.png" alt=""></a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/4-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/4-1.png" alt=""></a><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/5-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/5-1.png" alt=""></a></p> -<p>I was able to see the ‘supposed’ location of the log file by opening the Exchange Management Shell and running the ‘Get-MailboxDatabase’ cmdlet, like so:</p> -<p><em>Get-MailBoxDatabase –Identity <Recovery DB Name> | FL Name, ServerName, EDBFilePath, LogFolderPath</em></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/6.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/6.png" alt=""></a></p> -<p>I’m not sure why the database mounting process isn’t capable of creating the log file directory… I think Microsoft would have thought and planned for a situation like this. Hope this helps!</p> - + http://localhost:1313/posts/2015-08-12-failed-to-mount-exchange-2010-database/ + Recently, one of my users’ came to me and said he was missing two months worth of email. This was just after migrating to Exchange Online. We were using Exchange 2010 with System Center DPM for backups. I restored the database that the users’ mailbox was on from a backup then copied it over to the Exchange server from the network share I restored it to. All was going well, until I tried to mount the darn thing. - diff --git a/public/tags/exchange/page/1/index.html b/public/tags/exchange/page/1/index.html index 343ad8c4..74a34f25 100644 --- a/public/tags/exchange/page/1/index.html +++ b/public/tags/exchange/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/exchange/ - + http://localhost:1313/tags/exchange/ + - + diff --git a/public/tags/failed-pod/index.html b/public/tags/failed-pod/index.html index f79bf64c..82f4e5dd 100644 --- a/public/tags/failed-pod/index.html +++ b/public/tags/failed-pod/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Failed Pod · GeekyRyan + - - -failed pod - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,301 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Tag: failed pod

    - - - -
    -
    -
    -

    Kubernetes Pod Eviction

    -
    -
    +
    +
    + © -
    - In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation. -What is Pod Eviction? Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/failed-pod/index.xml b/public/tags/failed-pod/index.xml index e599ba16..4d6100b0 100644 --- a/public/tags/failed-pod/index.xml +++ b/public/tags/failed-pod/index.xml @@ -1,85 +1,19 @@ - failed pod on GeekyRyan - https://rnemeth90.github.io/tags/failed-pod/ - GeekyRyan (failed pod) - Hugo -- gohugo.io - en-us + Failed Pod on GeekyRyan + http://localhost:1313/tags/failed-pod/ + Recent content in Failed Pod on GeekyRyan + Hugo + en Sat, 05 Feb 2022 23:49:16 +0000 - - - - + Kubernetes Pod Eviction - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ Sat, 05 Feb 2022 23:49:16 +0000 - - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ - <p>In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation.</p> -<h2 id="what-is-pod-eviction" >What is Pod Eviction? -<span> - <a href="#what-is-pod-eviction"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. The most common of which is resource starvation on a node. This is referred to as “node-pressure eviction.”</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>NAME READY STATUS RESTARTS AGE -</span></span><span style="display:flex;"><span>nginx 0/1 Evicted <span style="color:#ae81ff">0</span> 10s -</span></span></code></pre></div><h2 id="eviction-process" >Eviction Process -<span> - <a href="#eviction-process"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The kubelet process running on the node monitors resources such as CPU, memory, disk space, inodes, etc. When one of these resources reaches a certain consumption level, the kubelet will first attempt to clean up resources by deleting non-running pods and images (in the case of storage starvation). The kubelet will then fail one or more pods on the node to reclaim resources. The class of the pod determines the order in which it does this.</p> -<p><strong>Pod Classes</strong></p> -<ul> -<li>Guaranteed: Pods that have requests and limits configured for both CPU and memory</li> -<li>Burstable: Pods with a resource request configured for memory or CPU</li> -<li>Best Effort: Pods without any requests or limits</li> -</ul> -<p>The kubelet will first evict any “best-effort” pods. If this is not enough, the kubelet will evict any “burstable” pods. Pods within the “guaranteed” class are theoretically safe from eviction.</p> -<p>During a node-pressure eviction, the kubelet sets the PodPhase for the selected pods to “Failed.” This causes the pods to terminate. If a daemonSet or replicaSet manages the pod, the Kubernetes controller-manager will create new pods on another node.</p> -<h2 id="recovery" >Recovery -<span> - <a href="#recovery"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Node-pressure eviction is almost always avoidable. We can prevent this type of issue by ensuring that we properly size our clusters and create resource limits for pods.</p> -<p><strong>Resource</strong> <strong>Requests and Limits:</strong></p> -<ul> -<li>Requests: The minimum amount of resources (CPU/memory) that a container needs to start.</li> -<li>Limits: The maximum amount of resources that a container is allowed to use.</li> -</ul> -<p>Pod resources and requests can be defined in a pod spec or deployment spec. Below is an example of a pod spec with resource requests and limits defined:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">frontend</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">nginx</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;64Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;250m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">limits</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;128Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;500m&#34;</span> -</span></span></code></pre></div><p>You will often need to clean up evicted pods manually. If you find that your cluster has a large amount of evicted pods, you can clean them up with the following kubectl commands:</p> -<p><strong>To see all failed pods in the cluster:</strong></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl get pod --all-namespaces --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Failed -</span></span></code></pre></div><p><strong>To remove all failed pods in the cluster:</strong></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl delete pod --all-namespaces --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Failed -</span></span></code></pre></div><p>I hope this article has been helpful. Please reach out if you have any questions or comments! Also, if you would like to learn more, take a look at the official Kubernetes docs:</p> -<p><a href="https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/">https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/</a></p> - + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ + In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation. What is Pod Eviction? Link to heading Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. - diff --git a/public/tags/failed-pod/page/1/index.html b/public/tags/failed-pod/page/1/index.html index 4c514797..8deabae2 100644 --- a/public/tags/failed-pod/page/1/index.html +++ b/public/tags/failed-pod/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/failed-pod/ - + http://localhost:1313/tags/failed-pod/ + - + diff --git a/public/tags/ftp/index.html b/public/tags/ftp/index.html index 96def055..a6637e1c 100644 --- a/public/tags/ftp/index.html +++ b/public/tags/ftp/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Ftp · GeekyRyan + - - -ftp - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,300 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Tag: ftp

    - - - -
    -
    -
    -

    Azure Kubernetes sFTP Solution

    -
    -
    +
    +
    + © -
    - In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault. -Here is the link to my Github account where you can download the code mentioned in this article: -https://github.com/rnemeth90/kubernetes-sftp -We will work through the following steps in this article: -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/ftp/index.xml b/public/tags/ftp/index.xml index ed2f3837..e9431f4d 100644 --- a/public/tags/ftp/index.xml +++ b/public/tags/ftp/index.xml @@ -1,198 +1,19 @@ - ftp on GeekyRyan - https://rnemeth90.github.io/tags/ftp/ - GeekyRyan (ftp) - Hugo -- gohugo.io - en-us + Ftp on GeekyRyan + http://localhost:1313/tags/ftp/ + Recent content in Ftp on GeekyRyan + Hugo + en Sun, 16 Jan 2022 07:00:00 +0000 - - - - + Azure Kubernetes sFTP Solution - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ + http://localhost:1313/posts/2022-01-16-azure-kubernetes-sftp-solution/ Sun, 16 Jan 2022 07:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ - <p>In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault.</p> -<p>Here is the link to my Github account where you can download the code mentioned in this article:</p> -<p><a href="https://github.com/rnemeth90/kubernetes-sftp">https://github.com/rnemeth90/kubernetes-sftp</a></p> -<p>We will work through the following steps in this article:</p> -<ol> -<li>Deploy the AzureFile CSI driver to the AKS cluster</li> -<li>Create a configMap that our initContainer will</li> -<li>Deploy a persistent volume claim that an Azure File share will back</li> -<li>Deploy a replicaSet consisting of our initContainer and application container</li> -<li>Deploy a service to serve traffic</li> -</ol> -<p>First, you will need to deploy the Azure Files CSI driver to your AKS cluster. AKS uses this daemon set to dynamically provision/destroy Azure NFSv4 File Shares. The Azure Files CSI driver creates a storage account in the node pool resource group, in which it will then provision the file share.</p> -<p>Deploying the Azure Files CSI driver is a simple task. You will need to run this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/install-driver.sh | bash -s master -- -</span></span></code></pre></div><p>You can use the following commands to verify that the daemon set has exists:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl -n kube-system get pod -o wide --watch -l app<span style="color:#f92672">=</span>csi-azurefile-controller -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>kubectl -n kube-system get pod -o wide --watch -l app<span style="color:#f92672">=</span>csi-azurefile-node -</span></span></code></pre></div><figure class="wp-block-coblocks-gallery-masonry masonry-grid has-border-radius-10 has-medium-gutter"><figure class="wp-block-image size-large masonry-brick">[![Image gallery image](https://rnemeth90.github.io/wp-content/uploads/2022/01/image-1-1024x434.png)](https://rnemeth90.github.io/wp-content/uploads/2022/01/image-1.png)</figure></figure>Next, you need to create a storage class by deploying this yaml file: -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl create -f https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/example/storageclass-azurefile-nfs.yaml -</span></span></code></pre></div><p>Read more about the AzureFiles CSI driver at the following Github link:</p> -<p><a href="https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/install-driver-on-aks.md">https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/install-driver-on-aks.md</a></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ConfigMap</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">creationTimestamp</span>: <span style="color:#66d9ef">null</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">testcm</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">init.sh</span>: |-<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> #!/bin/bash -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> CONF_FILE=&#34;/etc/sftp/users.conf&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> KEYVAULT=&#34;Insert name of Key Vault&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_ID=&#34;Insert service principal Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_PASSWORD=&#34;Insert service principal password&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_TENANT_ID=&#34;Insert Az AAD Tenant Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SUBSCRIPTION_ID=&#34;Insert Az Subscription Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az login --service-principal --username &#34;${AZ_SPN_ID}&#34; --password &#34;${AZ_SPN_PASSWORD}&#34; --tenant &#34;${AZ_SPN_TENANT_ID}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az account set --subscription &#34;${AZ_SUBSCRIPTION_ID}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETS+=($(az keyvault secret list --vault-name $KEYVAULT --query &#34;[].id&#34; -o tsv)) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> chmod 755 /home -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [[ -e $CONF_FILE ]]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> rm -rf &#34;${CONF_FILE}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> touch $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> else -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> touch $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> for SECRET in &#34;${SECRETS[@]}&#34;; do -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETNAME=$(basename $SECRET | tr -d &#39;\r&#39;) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETVALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $SECRETNAME --query &#39;value&#39; | tr -d &#39;&#34;&#39; | tr -d &#39;\r&#39;) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;$SECRETNAME:$SECRETVALUE:::upload&#34; &gt;&gt; $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> done -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [[ ! -s $CONF_FILE ]]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;** ERROR: user.conf is empty&#34; 1&gt;&amp;2 -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> exit 1 -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi</span> -</span></span></code></pre></div><p>The initContainer will use this configMap to read secrets from an Azure Key Vault and then write the secrets to the users.conf file. The users.conf file contains user account information. In the Key Vault, the secret name should be the username and the secret value should be the password. This Key Vault must exist and contain the secrets prior to deploying this solution.</p> -<p>When I deployed this solution in my environment, I used an Azure DevOps pipeline to create/manage the Key Vault with Terraform and then deploy the secrets using an inline Powershell script. However, this is beyond the scope of this article, and I will not be covering it here. You will also need to create a Service Principal in your AAD tenant and grant it access to the Key Vault. The Service Principal needs to have at least read access to the Key Vault.</p> -<p>Before deploying the configMap, you need to fill in values for these variables:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span> KEYVAULT<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert name of Key Vault&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert service principal Id&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_PASSWORD<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert service principal password&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_TENANT_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert Az AAD Tenant Id&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SUBSCRIPTION_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert Az Subscription Id&#34;</span> -</span></span></code></pre></div><p>These values pertain to the service principal with read access to the Key Vault. After filling out these variables, you can deploy the configMap using kubectl.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl create -f configmap.yaml -</span></span></code></pre></div><p>You can deploy the PVC using this yaml file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">azurefile-csi-nfs</span> -</span></span></code></pre></div><p>When creating the persistent volume claim for the deployment, you specify azurefile-csi-nfs as the StorageClass. This will create an NFSv4 share in a premium storage account. The reclaim policy of the storage class ensures that the file share is deleted when the associated Persistent Volume is deleted. Change the reclaim policy to “Retain” if you want the file shares to persist after deleting the PV. Furthermore, the storage class enables the file share to be expandable by modifying the storage request size on the PVC.</p> -<p>After deploying the PVC, you can verify its existence by running:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl get pvc -</span></span></code></pre></div><p>You should see output similar to the following (the manifest for the replicaSet is by far the most complicated of all the code referenced here):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Deployment</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">matchLabels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">strategy</span>: {} -</span></span><span style="display:flex;"><span> <span style="color:#f92672">template</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initContainer</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">chmodder</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">mcr.microsoft.com/azure-cli</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">command</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">/bin/sh</span> -</span></span><span style="display:flex;"><span> - -<span style="color:#ae81ff">c</span> -</span></span><span style="display:flex;"><span> - <span style="color:#e6db74">&#34;/scripts/init.sh&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/scripts</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">docker.io/atmoz/sftp:alpine</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">imagePullPolicy</span>: <span style="color:#ae81ff">IfNotPresent</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;64Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;250m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">limits</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;128Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;500m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">livenessProbe</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tcpSocket</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initialDelaySeconds</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">timeoutSeconds</span>: <span style="color:#ae81ff">5</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">periodSeconds</span>: <span style="color:#ae81ff">10</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">failureThreshold</span>: <span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readinessProbe</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tcpSocket</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initialDelaySeconds</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">timeoutSeconds</span>: <span style="color:#ae81ff">5</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">periodSeconds</span>: <span style="color:#ae81ff">10</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">failureThreshold</span>: <span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/home</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/etc/sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">dnsPolicy</span>: <span style="color:#ae81ff">ClusterFirst</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">restartPolicy</span>: <span style="color:#ae81ff">Never</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">configMap</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">emptyDir</span>: {} -</span></span></code></pre></div><p>You may need to change the CPU/memory requests and limits. These values worked for me, but your results may vary. You can also add/change the labels as you see fit.</p> -<p>This will handle routing traffic to our pods.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Service</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp-service</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">LoadBalancer</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">ports</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">protocol</span>: <span style="color:#ae81ff">TCP</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">targetPort</span>: <span style="color:#ae81ff">22</span> -</span></span></code></pre></div><p>Users will be connected in a round-robin fashion to the pods. This manifest will create a service of type LoadBalancer. Which will in turn create a new public Azure Load Balancer in the resource group that contains your Azure Kubernetes Service cluster if one does not already exist. If you already have a public load balancer, a new frontend IP address will be added.</p> -<p>That’s all for now. Please feel free to contact me if you have any questions.</p> - + http://localhost:1313/posts/2022-01-16-azure-kubernetes-sftp-solution/ + In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault. Here is the link to my Github account where you can download the code mentioned in this article: https://github.com/rnemeth90/kubernetes-sftp We will work through the following steps in this article: - diff --git a/public/tags/ftp/page/1/index.html b/public/tags/ftp/page/1/index.html index 79b71832..b614a55c 100644 --- a/public/tags/ftp/page/1/index.html +++ b/public/tags/ftp/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/ftp/ - + http://localhost:1313/tags/ftp/ + - + diff --git a/public/tags/github-actions/index.html b/public/tags/github-actions/index.html index 6ea7ea13..4dfb5eb8 100644 --- a/public/tags/github-actions/index.html +++ b/public/tags/github-actions/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Github-Actions · GeekyRyan + - - -github-actions - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,295 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Tag: github-actions

    - - - -
    -
    -
    -

    Building a Golang App with Github Actions

    -
    -
    +
    +
    + © -
    - In this article, we’ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app written in any language though. We’ll cover the following: -What are github actions? Setting up the workflow to build, test, and deploy a binary Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-12-24-gh-actions-copy/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/github-actions/index.xml b/public/tags/github-actions/index.xml index fbef1c8e..ef5305a6 100644 --- a/public/tags/github-actions/index.xml +++ b/public/tags/github-actions/index.xml @@ -1,119 +1,19 @@ - github-actions on GeekyRyan - https://rnemeth90.github.io/tags/github-actions/ - GeekyRyan (github-actions) - Hugo -- gohugo.io - en-us + Github-Actions on GeekyRyan + http://localhost:1313/tags/github-actions/ + Recent content in Github-Actions on GeekyRyan + Hugo + en Fri, 23 Dec 2022 00:00:00 +0000 - - - - + Building a Golang App with Github Actions - https://rnemeth90.github.io/posts/2022-12-24-gh-actions-copy/ + http://localhost:1313/posts/2022-12-24-gh-actions-copy/ Fri, 23 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-24-gh-actions-copy/ - <p>In this article, we&rsquo;ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app -written in any language though. We&rsquo;ll cover the following:</p> -<ol> -<li>What are github actions?</li> -<li>Setting up the workflow to build, test, and deploy a binary</li> -</ol> -<p>Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. They are powerful and I suggest you read more at the <a href="https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions">Official Docs</a></p> -<p>To get started, we&rsquo;ll need a golang app to build. You can use my example <a href="https://github.com/rnemeth90/golang-github-action-example">here</a> if you do not have your own.</p> -<p>The process is relatively simple. At the root of your repo, create the following directories:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>mkdir -p .github/workflows -</span></span></code></pre></div><p>Then create a yaml file (you can name it anything you want) with the content below:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">name</span>: <span style="color:#ae81ff">build-release-binary</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">run-name</span>: <span style="color:#ae81ff">Create Github Release for GoLang binary</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># anytime we push to our repo with a tag starting with the</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># letter &#39;r&#39;, we run the build</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">on</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">push</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tags</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#e6db74">&#39;r*&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">jobs</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">build</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">runs-on</span>: <span style="color:#ae81ff">ubuntu-22.04</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">permissions</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">contents</span>: <span style="color:#ae81ff">write</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># checkout our github repo to the build agent</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/checkout@v3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">fetch-depth</span>: <span style="color:#ae81ff">0</span> <span style="color:#75715e"># get all tags, needed to get git log</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">ref</span>: <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Setup the Go environment</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">setup Go Lang</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">id</span>: <span style="color:#ae81ff">build</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/setup-go@v3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">go-version</span>: <span style="color:#e6db74">&#39;^1.19.2&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Build our application</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go version -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> cd src -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [ ! -e *.mod ]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go mod init ${GITHUB_REPOSITORY} -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go mod tidy -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go build -ldflags &#34;-X main.Version=${GITHUB_REF_NAME} -X main.BuiltBy=github-actions&#34; main.go -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> execFile=$(find . -type f -executable)</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Output more values for debugging</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git version</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git branch</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git tag</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># tag our release</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">get semantic tag version and release notes from commit messages</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">id</span>: <span style="color:#ae81ff">tag</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">run</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> currentTag=${GITHUB_REF_NAME} -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> major_minor=$(echo &#34;$currentTag&#34; | cut -d&#39;.&#39; -f1-2) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> patch=$(echo &#34;$currentTag&#34; | cut -d&#39;.&#39; -f3) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> # avoid empty patch number -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> [ -n &#34;$patch&#34; ] &amp;&amp; ((patch--)) || patch=&#34;.x&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> previousTag=&#34;${major_minor}.${patch}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;&#34; &gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if git tag | grep $previousTag ; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git log -q ${currentTag}...${previousTag} --pretty=&#34;- %s&#34; -q --no-color &gt;&gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> else -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git log --pretty=&#34;- %s&#34; -q --no-color &gt;&gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> line_count=$(cat body.log | wc -l) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;currentTag=$currentTag&#34; &gt;&gt; $GITHUB_OUTPUT -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;previousTag=$previousTag&#34; &gt;&gt; $GITHUB_OUTPUT -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;line_count=$line_count&#34; &gt;&gt; $GITHUB_OUTPUT</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># create Github release with release note from file and binary asset attached</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">ncipollo/release-action@v1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">${{ env.GITHUB_REF_NAME }}</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tag</span>: <span style="color:#ae81ff">${{ env.GITHUB_REF_NAME }}</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">artifacts</span>: <span style="color:#e6db74">&#34;src/main&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">bodyFile</span>: <span style="color:#e6db74">&#34;body.log&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">token</span>: <span style="color:#ae81ff">${{ secrets.GITHUB_TOKEN }}</span> -</span></span></code></pre></div><p>Each step within this workflow starts with a hyphen. The steps are well-commented, so I will not explain them further. Once you have this file in your repo, push it to github. Then navigate to the Actions tab in your repository and you should see your workflow on the left hand side of the screen.</p> -<p><a href="https://rnemeth90.github.io/images/gh-actions-1.png"><img src="https://rnemeth90.github.io/images/gh-actions-1.png" alt=""></a></p> -<p>Now that we have our workflow setup, to get it run, all you need to do is tag and push your release to github. To do that, you can run the script in my repo <a href="https://github.com/rnemeth90/golang-github-action-example/blob/main/create_new_gh_release.sh">create_new_gh_release.sh</a> or simply run the following commands (be sure to change the tag as needed):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>newtag<span style="color:#f92672">=</span>r1.0.0 -</span></span><span style="display:flex;"><span>git tag $newtag <span style="color:#f92672">&amp;&amp;</span> git push origin $newtag -</span></span></code></pre></div><p>Now, go back to the Actions tab in your repo, and you should see the build running. Once it completes, go back to the Code tab in your github repo and you will see the release on the right hand side of the screen.</p> -<p><a href="https://rnemeth90.github.io/images/gh-actions-2.png"><img src="https://rnemeth90.github.io/images/gh-actions-2.png" alt=""></a></p> - + http://localhost:1313/posts/2022-12-24-gh-actions-copy/ + In this article, we&rsquo;ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app written in any language though. We&rsquo;ll cover the following: What are github actions? Setting up the workflow to build, test, and deploy a binary Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. - diff --git a/public/tags/github-actions/page/1/index.html b/public/tags/github-actions/page/1/index.html index 01c0b7fb..44d91f24 100644 --- a/public/tags/github-actions/page/1/index.html +++ b/public/tags/github-actions/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/github-actions/ - + http://localhost:1313/tags/github-actions/ + - + diff --git a/public/tags/golang/index.html b/public/tags/golang/index.html index a49734e5..ddc2a532 100644 --- a/public/tags/golang/index.html +++ b/public/tags/golang/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Golang · GeekyRyan + - + -golang - GeekyRyan - + + + - - - + + + + + + + + + - - + - + + + + + + - - - - - - - - - - - - - - - - - - + - - - - - - - - - - + + + - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,504 +79,181 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - + + + - - - - - - - - -
    -
    - -

    Tag: golang

    - - - -
    -
    -
    -

    Golang: When Identical Strings are Not Equal

    -
    - -
    - - -
    - This will be a quick and dirty post, so please forgive any spelling/grammar mistakes. -I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don’t write a ton of code at work (mostly just scripting/pipelines when I do), so I’m constantly working on something like this in my spare time. -
    - - -
    - Read more -
    - - - +
    +
    - -
    -
    -
    -

    Building a Golang App with Github Actions

    -
    -
    - - -
    - In this article, we’ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app written in any language though. We’ll cover the following: -What are github actions? Setting up the workflow to build, test, and deploy a binary Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. -
    - - -
    - Read more -
    + - - - - - - - - -
    +
    + +
    +
    +

    + Tag: Golang +

    +
    + + + - - +
    + - - -
    -
    -
    -

    Reading Json Files with Go

    -
    -
    +
    +
    + © -
    - JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting with it, and most public APIs accept JSON in HTTP requests. -In this post, we’ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the JSON data within the file into a memory structure. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - +
    +
    -
    - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/golang/index.xml b/public/tags/golang/index.xml index 72737955..8708650b 100644 --- a/public/tags/golang/index.xml +++ b/public/tags/golang/index.xml @@ -1,393 +1,54 @@ - golang on GeekyRyan - https://rnemeth90.github.io/tags/golang/ - GeekyRyan (golang) - Hugo -- gohugo.io - en-us - Tue, 24 Jan 2023 00:00:00 +0000 - - - - + Golang on GeekyRyan + http://localhost:1313/tags/golang/ + Recent content in Golang on GeekyRyan + Hugo + en + Wed, 27 Mar 2024 00:00:00 +0000 + + + Detecting MIME Types in Go + http://localhost:1313/posts/2024-03-27-golang-detect-file-type/ + Wed, 27 Mar 2024 00:00:00 +0000 + http://localhost:1313/posts/2024-03-27-golang-detect-file-type/ + Introduction Link to heading Knowing the type of a file you&rsquo;re working with is not just a matter of curiosity — it&rsquo;s often a necessity. This is especially true when you&rsquo;re deciding whether or not a particular operation can be carried out on that file. Go, with its comprehensive standard library, offers a straightforward approach to identifying a file&rsquo;s MIME type, ensuring that developers have the tools they need to make informed decisions about file manipulation. + + + Validating URLs with Go + http://localhost:1313/posts/2023-12-12-golang-url-validation/ + Tue, 19 Dec 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-12-12-golang-url-validation/ + Introduction Link to heading In this post, we&rsquo;ll take a quick look at URL validation using Golang. It&rsquo;s common to implement URL validation as a task within a HTTP request pipeline, typically as middleware. There are many different definitions of &ldquo;validation&rdquo;. For the purpose of this article, we will simply validate that a URL conforms to a particular text pattern. I often see people (mistakenly) use URL and URI interchangeably. + Golang: When Identical Strings are Not Equal - https://rnemeth90.github.io/posts/2023-01-24-golang-strings-not-equal/ + http://localhost:1313/posts/2023-01-24-golang-strings-not-equal/ Tue, 24 Jan 2023 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2023-01-24-golang-strings-not-equal/ - <p><em>This will be a quick and dirty post, so please forgive any spelling/grammar mistakes.</em></p> -<p>I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don&rsquo;t write a ton of code at work (mostly just scripting/pipelines when I do), so I&rsquo;m constantly working on something like this in my spare time. Anyway, I was writing this app, got everything working like I wanted it to. I then wrote some of the tests and was iterating over them. I noticed the <code>ListTasks</code> test was failing:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TestAddTask</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">task</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;test task number 1&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Getwd</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmdPath</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">binaryName</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;AddNewTask&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-add&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">Run</span>(); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// failing test -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;ListTasks&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-list&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">out</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">CombinedOutput</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">expected</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;[ ] 1: %s&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Compare</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#a6e22e">expected</span>) <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;got %v, expected %v\n&#34;</span>, <span style="color:#a6e22e">out</span>, []byte(<span style="color:#a6e22e">expected</span>)) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Seems strange, considering the strings appear to be equivalent in the output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span> main_test.go:82: got <span style="color:#f92672">[</span> <span style="color:#f92672">]</span> 1: test task number <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> , expected <span style="color:#f92672">[</span> <span style="color:#f92672">]</span> 1: test task number <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>--- FAIL: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- FAIL: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>FAIL -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>exit status <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>FAIL github.com/rnemeth90/todo/cmd/todo 0.105s -</span></span></code></pre></div><p>What could be happening? After banging my head on the desk a few times, a revelation came to me&hellip;</p> -<p>In Go, strings are simply slices of bytes. I decided to print out each string as a byte array:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span> main_test.go:80: got <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">10</span> 10<span style="color:#f92672">]</span>, expected <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> 49<span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span>--- FAIL: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- FAIL: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>FAIL -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>exit status <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>FAIL github.com/rnemeth90/todo/cmd/todo 0.144s -</span></span></code></pre></div><p>Let&rsquo;s take a closer look at the byte arrays from the test output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>got <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">10</span> 10<span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span>expected <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> 49<span style="color:#f92672">]</span> -</span></span></code></pre></div><p>We can see the byte array returned from <code>cmd.CombinedOutput()</code> has some additional bytes in it at the end (32,10,10). What exactly are 32, 10, and 10? To figure this out, I went over to the go playground: <a href="https://go.dev/play/">https://go.dev/play/</a>.</p> -<p>Let&rsquo;s see what happens when we create a byte array with a single number and print it out as a string to the console:</p> -<p><a href="https://rnemeth90.github.io/images/golang-strings-not-equal-01.png"><img src="https://rnemeth90.github.io/images/golang-strings-not-equal-01.png" alt=""></a></p> -<p>Interesting, we can see that <code>m</code> was output to the console. So what do our mysterious additional characters in our test result represent? Let&rsquo;s see:</p> -<p><a href="https://rnemeth90.github.io/images/golang-strings-not-equal-02.png"><img src="https://rnemeth90.github.io/images/golang-strings-not-equal-02.png" alt=""></a></p> -<p>It&rsquo;s hard to tell from the output, but if you look in the results pane, you&rsquo;ll see a space and two new lines. So <code>32</code> represents a space, and <code>10</code> represents a new line!</p> -<p>You can play with this code yourself: <a href="https://go.dev/play/p/fGUIxJM6KnV">https://go.dev/play/p/fGUIxJM6KnV</a></p> -<p>Ok, so let&rsquo;s fix our failing test:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TestAddTask</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">task</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;test task number 1&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Getwd</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmdPath</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">binaryName</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;AddNewTask&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-add&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">Run</span>(); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;ListTasks&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-list&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">out</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">CombinedOutput</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// add this line -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">out</span> = []byte(<span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">TrimSuffix</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#e6db74">&#34; \n\n&#34;</span>)) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">expected</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;[ ] 1: %s&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Compare</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#a6e22e">expected</span>) <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;got %v, expected %v\n&#34;</span>, <span style="color:#a6e22e">out</span>, []byte(<span style="color:#a6e22e">expected</span>)) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>The <code>strings</code> package has a <code>TrimSuffix</code> function that is useful for trimming bits off the end of a string. In the code above, you can see that we added <code>out = []byte(strings.TrimSuffix(string(out), &quot; \n\n&quot;))</code>, which will trim off the space (character 32) and the two new lines (character 10). Now when we run our integration test, it passes:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span>--- PASS: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>PASS -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>ok github.com/rnemeth90/todo/cmd/todo 0.106s -</span></span></code></pre></div> + http://localhost:1313/posts/2023-01-24-golang-strings-not-equal/ + This will be a quick and dirty post, so please forgive any spelling/grammar mistakes. I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don&rsquo;t write a ton of code at work (mostly just scripting/pipelines when I do), so I&rsquo;m constantly working on something like this in my spare time. - Building a Golang App with Github Actions - https://rnemeth90.github.io/posts/2022-12-24-gh-actions-copy/ + http://localhost:1313/posts/2022-12-24-gh-actions-copy/ Fri, 23 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-24-gh-actions-copy/ - <p>In this article, we&rsquo;ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app -written in any language though. We&rsquo;ll cover the following:</p> -<ol> -<li>What are github actions?</li> -<li>Setting up the workflow to build, test, and deploy a binary</li> -</ol> -<p>Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. They are powerful and I suggest you read more at the <a href="https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions">Official Docs</a></p> -<p>To get started, we&rsquo;ll need a golang app to build. You can use my example <a href="https://github.com/rnemeth90/golang-github-action-example">here</a> if you do not have your own.</p> -<p>The process is relatively simple. At the root of your repo, create the following directories:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>mkdir -p .github/workflows -</span></span></code></pre></div><p>Then create a yaml file (you can name it anything you want) with the content below:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">name</span>: <span style="color:#ae81ff">build-release-binary</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">run-name</span>: <span style="color:#ae81ff">Create Github Release for GoLang binary</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># anytime we push to our repo with a tag starting with the</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># letter &#39;r&#39;, we run the build</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">on</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">push</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tags</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#e6db74">&#39;r*&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">jobs</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">build</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">runs-on</span>: <span style="color:#ae81ff">ubuntu-22.04</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">permissions</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">contents</span>: <span style="color:#ae81ff">write</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># checkout our github repo to the build agent</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/checkout@v3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">fetch-depth</span>: <span style="color:#ae81ff">0</span> <span style="color:#75715e"># get all tags, needed to get git log</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">ref</span>: <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Setup the Go environment</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">setup Go Lang</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">id</span>: <span style="color:#ae81ff">build</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/setup-go@v3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">go-version</span>: <span style="color:#e6db74">&#39;^1.19.2&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Build our application</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go version -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> cd src -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [ ! -e *.mod ]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go mod init ${GITHUB_REPOSITORY} -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go mod tidy -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> go build -ldflags &#34;-X main.Version=${GITHUB_REF_NAME} -X main.BuiltBy=github-actions&#34; main.go -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> execFile=$(find . -type f -executable)</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Output more values for debugging</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git version</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git branch</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">run</span>: <span style="color:#ae81ff">git tag</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># tag our release</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">get semantic tag version and release notes from commit messages</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">id</span>: <span style="color:#ae81ff">tag</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">run</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> currentTag=${GITHUB_REF_NAME} -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> major_minor=$(echo &#34;$currentTag&#34; | cut -d&#39;.&#39; -f1-2) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> patch=$(echo &#34;$currentTag&#34; | cut -d&#39;.&#39; -f3) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> # avoid empty patch number -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> [ -n &#34;$patch&#34; ] &amp;&amp; ((patch--)) || patch=&#34;.x&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> previousTag=&#34;${major_minor}.${patch}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;&#34; &gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if git tag | grep $previousTag ; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git log -q ${currentTag}...${previousTag} --pretty=&#34;- %s&#34; -q --no-color &gt;&gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> else -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git log --pretty=&#34;- %s&#34; -q --no-color &gt;&gt; body.log -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> line_count=$(cat body.log | wc -l) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;currentTag=$currentTag&#34; &gt;&gt; $GITHUB_OUTPUT -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;previousTag=$previousTag&#34; &gt;&gt; $GITHUB_OUTPUT -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;line_count=$line_count&#34; &gt;&gt; $GITHUB_OUTPUT</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># create Github release with release note from file and binary asset attached</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">ncipollo/release-action@v1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">with</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">${{ env.GITHUB_REF_NAME }}</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tag</span>: <span style="color:#ae81ff">${{ env.GITHUB_REF_NAME }}</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">artifacts</span>: <span style="color:#e6db74">&#34;src/main&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">bodyFile</span>: <span style="color:#e6db74">&#34;body.log&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">token</span>: <span style="color:#ae81ff">${{ secrets.GITHUB_TOKEN }}</span> -</span></span></code></pre></div><p>Each step within this workflow starts with a hyphen. The steps are well-commented, so I will not explain them further. Once you have this file in your repo, push it to github. Then navigate to the Actions tab in your repository and you should see your workflow on the left hand side of the screen.</p> -<p><a href="https://rnemeth90.github.io/images/gh-actions-1.png"><img src="https://rnemeth90.github.io/images/gh-actions-1.png" alt=""></a></p> -<p>Now that we have our workflow setup, to get it run, all you need to do is tag and push your release to github. To do that, you can run the script in my repo <a href="https://github.com/rnemeth90/golang-github-action-example/blob/main/create_new_gh_release.sh">create_new_gh_release.sh</a> or simply run the following commands (be sure to change the tag as needed):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>newtag<span style="color:#f92672">=</span>r1.0.0 -</span></span><span style="display:flex;"><span>git tag $newtag <span style="color:#f92672">&amp;&amp;</span> git push origin $newtag -</span></span></code></pre></div><p>Now, go back to the Actions tab in your repo, and you should see the build running. Once it completes, go back to the Code tab in your github repo and you will see the release on the right hand side of the screen.</p> -<p><a href="https://rnemeth90.github.io/images/gh-actions-2.png"><img src="https://rnemeth90.github.io/images/gh-actions-2.png" alt=""></a></p> - + http://localhost:1313/posts/2022-12-24-gh-actions-copy/ + In this article, we&rsquo;ll take a quick look at building a Golang app with Github actions. This process can be applied to just about any app written in any language though. We&rsquo;ll cover the following: What are github actions? Setting up the workflow to build, test, and deploy a binary Github Actions is a cross-platform CI/CD pipeline that allows you to build, test, package, and release your software. Actions can be triggered manually or based on events that happen within your Github repo. - Use “replace” in go.mod to Point to a Local Module - https://rnemeth90.github.io/posts/2022-09-06-go-mod-replace-copy/ + http://localhost:1313/posts/2022-09-06-go-mod-replace-copy/ Tue, 06 Sep 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-09-06-go-mod-replace-copy/ - <p>If you want to the local version of a dependency in Go rather than one in a remote repository, use the <em>replace</em> keyword.</p> -<p>The replace line goes above your require statements, like so:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> module github.com/rnemeth90/foo -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> replace github.com/rnemeth90/bar <span style="color:#f92672">=</span>&gt; /Users/rnemeth90/Projects/bar -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> require <span style="color:#f92672">(</span> -</span></span><span style="display:flex;"><span> github.com/rnemeth90/bar v1.0.0 -</span></span><span style="display:flex;"><span> <span style="color:#f92672">)</span> -</span></span></code></pre></div><p>Now when you compile this module <em>go build</em> or <em>go install</em>, it will use your local code rather than the remote dependency.</p> -<p>According to the docs, you do need to make sure that the code you’re pointing to also has a <strong>go.mod</strong> file:</p> -<blockquote> -<p><strong>Note</strong>: if the right-hand side of a <code>replace</code> directive is a filesystem path, then the target must have a <code>go.mod</code> file at that location. If the <code>go.mod</code> file is not present, you can create one with <code>go mod init</code>.</p> -<p><a href="https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive">https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive</a></p> -</blockquote> -<p>You can also create this line from the command line using the <strong>go mod edit</strong> command.</p> -<pre><code>$ go mod edit -replace github.com/rnemeth90/bar=/Users/rnemeth90/Projects/bar -</code></pre> -<p>Following the <strong>-replace</strong> is first what you want to replace, then an equals sign, then what you’re replacing it with.</p> -<p>Hopefully this helps someone who was stuck with this like me 🙂</p> - + http://localhost:1313/posts/2022-09-06-go-mod-replace-copy/ + If you want to the local version of a dependency in Go rather than one in a remote repository, use the replace keyword. The replace line goes above your require statements, like so: module github.com/rnemeth90/foo replace github.com/rnemeth90/bar =&gt; /Users/rnemeth90/Projects/bar require ( github.com/rnemeth90/bar v1.0.0 ) Now when you compile this module go build or go install, it will use your local code rather than the remote dependency. According to the docs, you do need to make sure that the code you’re pointing to also has a go. - Reading Json Files with Go - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ + http://localhost:1313/posts/2022-07-21-reading-json-files-with-go/ Thu, 21 Jul 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ - <p>JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting -with it, and most public APIs accept JSON in HTTP requests.</p> -<p>In this post, we&rsquo;ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the -JSON data within the file into a memory structure.</p> -<p>Let&rsquo;s assume we have the following JSON data representing an employee:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">1</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Steve&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Rogers&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Captain America&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Department&#34;</span>: <span style="color:#e6db74">&#34;Avengers&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>We need a way of representing this data in memory when decoding it from JSON. For this, we will need to create a struct:</p> -<p>We will build up our go module as we progress through the article</p> -<p>Let&rsquo;s start:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#75715e">// main.go -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> ( -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;encoding/json&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;fmt&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;io/ioutil&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;log&#34;</span> -</span></span><span style="display:flex;"><span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">// Hero represents an hero -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// ALL fields must be exportable! Otherwise the JSON parsing will fail. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Hero</span> <span style="color:#66d9ef">struct</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Id</span> <span style="color:#66d9ef">int</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">FirstName</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">LastName</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Alias</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Group</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() { -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Here we set the log prefix. When reading stack traces, this makes it easier to know -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// where a failure occurred. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">SetPrefix</span>(<span style="color:#e6db74">&#34;main(): &#34;</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// We first need to load the JSON file into memory -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">content</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">ioutil</span>.<span style="color:#a6e22e">ReadFile</span>(<span style="color:#e6db74">&#34;./heros.json&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#e6db74">&#34;Error opening the file: &#34;</span>, <span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Now we parse the JSON data into a memory structure. We know our JSON file will have more than one hero object, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// so we&#39;ll use make() to create a []Hero slice. Since go is a pass-by-value language, we will then use the address-of -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// operator (&amp;) to unmarshal our json data into the heros slice -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">heros</span> <span style="color:#f92672">:=</span> make([]<span style="color:#a6e22e">Hero</span>, <span style="color:#ae81ff">5</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">json</span>.<span style="color:#a6e22e">Unmarshal</span>(<span style="color:#a6e22e">content</span>, <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">heros</span>) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#e6db74">&#34;Error occurred during unmarshal: &#34;</span>, <span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// now we can read/interact with the data. We&#39;ll loop over the array -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// and print the values in memory -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; len(<span style="color:#a6e22e">heros</span>); <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">Id</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">FirstName</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">LastName</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">Group</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Create a file named employees.json with similar data:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>[ -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">1</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Steve&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Rogers&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Captain America&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;group&#34;</span>: <span style="color:#e6db74">&#34;Avengers&#34;</span> -</span></span><span style="display:flex;"><span> }, -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">2</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Clark&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Kent&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Superman&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;group&#34;</span>: <span style="color:#e6db74">&#34;Justice League&#34;</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>] -</span></span></code></pre></div><p>Now, we can run our main.go file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>11:40:47 ryan@xerxes json → go run main.go -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>Steve -</span></span><span style="display:flex;"><span>Rogers -</span></span><span style="display:flex;"><span>Avengers -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span>Clark -</span></span><span style="display:flex;"><span>Kent -</span></span><span style="display:flex;"><span>Justice League -</span></span><span style="display:flex;"><span>11:40:49 ryan@xerxes json -</span></span></code></pre></div><p>Pretty simple! That&rsquo;s why I love go. We accomplished all of this with ~50 lines of code. -Doing something similar in asp.net project would easily double that count and involve creating -multiple files! (nothing against asp.net or c#, I think c# is a great language and use it daily)</p> -<p>Now, &lsquo;go&rsquo; try this!</p> - + http://localhost:1313/posts/2022-07-21-reading-json-files-with-go/ + JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting with it, and most public APIs accept JSON in HTTP requests. In this post, we&rsquo;ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the JSON data within the file into a memory structure. - diff --git a/public/tags/golang/page/1/index.html b/public/tags/golang/page/1/index.html index 8c688559..c2d28ec6 100644 --- a/public/tags/golang/page/1/index.html +++ b/public/tags/golang/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/golang/ - + http://localhost:1313/tags/golang/ + - + diff --git a/public/tags/index.html b/public/tags/index.html index 2446facd..93d2c9a3 100644 --- a/public/tags/index.html +++ b/public/tags/index.html @@ -1,733 +1,806 @@ + - - - - - - - + + Tags · GeekyRyan + - - -Tags - GeekyRyan - - + + + + - - - - + + + - + + + + + + - + + + + - - - - - + + + - - - + - + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - + + + + +
    + + + +
    + +
    +
    +

    + Tags +

    +
    + +
    - -
    - + +
    +
    + © + + 2012 - + + 2024 + Ryan Nemeth + · + + Powered by Hugo & Coder. + +
    +
    +
    + + + + + + - - -
    - -
    - -
    + -

    Tags

    - + + -
    - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/index.xml b/public/tags/index.xml index baa85d65..5c64e82a 100644 --- a/public/tags/index.xml +++ b/public/tags/index.xml @@ -2,14 +2,382 @@ Tags on GeekyRyan - https://rnemeth90.github.io/tags/ - GeekyRyan (Tags) - Hugo -- gohugo.io - en-us - Tue, 15 Aug 2023 00:00:00 +0000 - - - - + http://localhost:1313/tags/ + Recent content in Tags on GeekyRyan + Hugo + en + Sat, 29 Jun 2024 00:00:00 +0000 + + + Devops + http://localhost:1313/tags/devops/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/devops/ + + + + Software Development + http://localhost:1313/tags/software-development/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/software-development/ + + + + Web Development + http://localhost:1313/tags/web-development/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/web-development/ + + + + Golang + http://localhost:1313/tags/golang/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/golang/ + + + + Url + http://localhost:1313/tags/url/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/url/ + + + + Kubernetes + http://localhost:1313/tags/kubernetes/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/kubernetes/ + + + + Linux + http://localhost:1313/tags/linux/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/linux/ + + + + Nginx-Ingress + http://localhost:1313/tags/nginx-ingress/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/nginx-ingress/ + + + + Netcat + http://localhost:1313/tags/netcat/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/netcat/ + + + + Networking + http://localhost:1313/tags/networking/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/networking/ + + + + PowerShell + http://localhost:1313/tags/powershell/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/powershell/ + + + + C# + http://localhost:1313/tags/c%23/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/c%23/ + + + + Dotnet + http://localhost:1313/tags/dotnet/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/dotnet/ + + + + SRE + http://localhost:1313/tags/sre/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/sre/ + + + + Backup + http://localhost:1313/tags/backup/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/backup/ + + + + CI/CD + http://localhost:1313/tags/ci/cd/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/ci/cd/ + + + + Github-Actions + http://localhost:1313/tags/github-actions/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/github-actions/ + + + + Azure + http://localhost:1313/tags/azure/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/azure/ + + + + Software + http://localhost:1313/tags/software/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/software/ + + + + Dev + http://localhost:1313/tags/dev/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/dev/ + + + + Programming + http://localhost:1313/tags/programming/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/programming/ + + + + Json + http://localhost:1313/tags/json/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/json/ + + + + Rest + http://localhost:1313/tags/rest/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/rest/ + + + + Aks + http://localhost:1313/tags/aks/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/aks/ + + + + Azure Kubernetes Service + http://localhost:1313/tags/azure-kubernetes-service/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/azure-kubernetes-service/ + + + + Storage + http://localhost:1313/tags/storage/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/storage/ + + + + Docker + http://localhost:1313/tags/docker/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/docker/ + + + + Database + http://localhost:1313/tags/database/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/database/ + + + + Ef Core + http://localhost:1313/tags/ef-core/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/ef-core/ + + + + Entity Framework + http://localhost:1313/tags/entity-framework/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/entity-framework/ + + + + Bash + http://localhost:1313/tags/bash/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/bash/ + + + + Failed Pod + http://localhost:1313/tags/failed-pod/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/failed-pod/ + + + + Pod Eviction + http://localhost:1313/tags/pod-eviction/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/pod-eviction/ + + + + Ftp + http://localhost:1313/tags/ftp/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/ftp/ + + + + Software Deployment + http://localhost:1313/tags/software-deployment/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/software-deployment/ + + + + Certification + http://localhost:1313/tags/certification/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/certification/ + + + + ActiveDirectory + http://localhost:1313/tags/activedirectory/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/activedirectory/ + + + + Office365 + http://localhost:1313/tags/office365/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/office365/ + + + + VMSS + http://localhost:1313/tags/vmss/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/vmss/ + + + + Security + http://localhost:1313/tags/security/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/security/ + + + + Vmware + http://localhost:1313/tags/vmware/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/vmware/ + + + + WindowsServer + http://localhost:1313/tags/windowsserver/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/windowsserver/ + + + + Cisco + http://localhost:1313/tags/cisco/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/cisco/ + + + + Tools + http://localhost:1313/tags/tools/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/tools/ + + + + Windows Client OS + http://localhost:1313/tags/windows-client-os/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/windows-client-os/ + + + + AADConnect + http://localhost:1313/tags/aadconnect/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/aadconnect/ + + + + DirSync + http://localhost:1313/tags/dirsync/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/dirsync/ + + + + Exchange + http://localhost:1313/tags/exchange/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/exchange/ + + + + WSUS + http://localhost:1313/tags/wsus/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/wsus/ + + + + WDS + http://localhost:1313/tags/wds/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/wds/ + + + + Scripts + http://localhost:1313/tags/scripts/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/scripts/ + + + + DHCP + http://localhost:1313/tags/dhcp/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/dhcp/ + + + + Windows + http://localhost:1313/tags/windows/ + Mon, 01 Jan 0001 00:00:00 +0000 + http://localhost:1313/tags/windows/ + + diff --git a/public/tags/json/index.html b/public/tags/json/index.html index c2184b3c..fe49de43 100644 --- a/public/tags/json/index.html +++ b/public/tags/json/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Json · GeekyRyan + - - -json - GeekyRyan - - - - - - - - - - + - - + + + - - + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,372 +79,161 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    -
    -
    - -

    Tag: json

    - + 2022-08-04 + Powershell for Devops - Querying REST APIs with Powershell + +
  • + 2022-07-21 + Reading Json Files with Go +
  • -
    -
    -
    -

    Powershell for Devops - Querying REST APIs with Powershell

    -
    - -
    + + - -
    - This will be a short post on querying REST APIs with Powershell. -It’s hard to argue that REST APIs are the predominant technology for interacting with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) product without having to go through the exercise of a more complicated integration. REST APIs communicate in a common format, typically JSON. However, most will allow us to choose the response format by specifying an option in the ‘Accept’ header. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Reading Json Files with Go

    -
    -
    +
    +
    + © -
    - JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting with it, and most public APIs accept JSON in HTTP requests. -In this post, we’ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the JSON data within the file into a memory structure. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - +
    +
    -
    - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/json/index.xml b/public/tags/json/index.xml index 4c25e246..5b4b24fe 100644 --- a/public/tags/json/index.xml +++ b/public/tags/json/index.xml @@ -1,189 +1,26 @@ - json on GeekyRyan - https://rnemeth90.github.io/tags/json/ - GeekyRyan (json) - Hugo -- gohugo.io - en-us + Json on GeekyRyan + http://localhost:1313/tags/json/ + Recent content in Json on GeekyRyan + Hugo + en Thu, 04 Aug 2022 00:00:00 +0000 - - - - + Powershell for Devops - Querying REST APIs with Powershell - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ Thu, 04 Aug 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ - <p>This will be a short post on querying REST APIs with Powershell.</p> -<p>It&rsquo;s hard to argue that REST APIs are the predominant technology for interacting -with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) -product without having to go through the exercise of a more complicated integration. REST APIs communicate -in a common format, typically JSON. However, most will allow us to choose the response format by specifying an -option in the &lsquo;Accept&rsquo; header. Most languages provide a native method for interacting with -REST APIs. This objective for this post is to show you how simple this is with Powershell.</p> -<p>To get started, we&rsquo;ll need a public API to interact with. I&rsquo;m going to use <a href="https://icanhazdadjoke.com/">https://icanhazdadjoke.com/</a>, because -there is no authentication and no rate-limiting (two concepts we will cover in another post).</p> -<p>Calling the API is extremely simple:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -</span></span></code></pre></div><p>However, this results in the content being returned as plain text. This isn&rsquo;t ideal.</p> -<p>Let&rsquo;s pass the &lsquo;Accept&rsquo; header to tell the API the format we are expecting to be returned:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers -</span></span></code></pre></div><p>Output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>[<span style="color:#ae81ff">15</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">04</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">34</span>] C:\..\..\rnemeth90.github.io on <span style="color:#960050;background-color:#1e0010"></span>main <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#ae81ff">+1</span> <span style="color:#960050;background-color:#1e0010">❯</span> Invoke-RestMethod -Uri $url -Method Get -Headers $headers -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>id joke status -</span></span><span style="display:flex;"><span>-- ---- ------ -</span></span><span style="display:flex;"><span>3LmyXvsPfqc I don<span style="color:#e6db74">&#39;t trust stairs. They&#39;</span>re always up to something. <span style="color:#ae81ff">200</span> -</span></span></code></pre></div><p>That looks a little better. For those of you familiar with Powershell, the output above probably -looks completely normal. But for those not-so-familiar with Powershell, or those expecting -more of a &lsquo;json-esk&rsquo; output, this may look a bit&hellip; weird.</p> -<p>Powershell is an object oriented language. <strong>Everything is an object</strong> in Powershell, even the response -of this request. What you see in the output is simply the properties of the object.</p> -<p>Luckily Powershell provides us with a cmdlet to convert an object into json (aptly named: ConvertTo-Json). We can use it like this:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers | ConvertTo-Json -</span></span></code></pre></div><p>Here we are piping the output from Invoke-RestMethod to ConvertTo-Json. Pretty neat!</p> -<p>Output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>[<span style="color:#ae81ff">15</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">04</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">35</span>] C:\..\..\rnemeth90.github.io on <span style="color:#960050;background-color:#1e0010"></span>main <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#ae81ff">+1</span> <span style="color:#960050;background-color:#1e0010">❯</span> Invoke-RestMethod -Uri $url -Method Get -Headers $headers | Convertto-json -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;id&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#e6db74">&#34;AAdFBXnGlyd&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;joke&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#e6db74">&#34;If you walk into a forest and cut down a tree, but the tree doesn&#39;t understand why you cut it down, do you think it&#39;s stumped?&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;status&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#ae81ff">200</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Now, that looks more normal.</p> -<p>There is much more we can do with Invoke-RestMethod. The &lsquo;Method&rsquo; parameter of this cmdlet accepts any of the common -HTTP methods (GET, PUT, PATCH, DELETE, POST, HEAD). You can also specify other headers and a body (using the -body parameter).</p> -<p>Both of these parameters accept dictionaries:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Host&#39;</span> = <span style="color:#e6db74">&#39;MyServer&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>$body = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Eat&#39;</span> = <span style="color:#e6db74">&#39;Pizza&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers -Body $body | ConvertTo-Json -</span></span></code></pre></div><p>Unfortunately I won&rsquo;t be able to show the other HTTP methods, as this API only supports GET requests. So that&rsquo;s all for now.</p> - + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ + This will be a short post on querying REST APIs with Powershell. It&rsquo;s hard to argue that REST APIs are the predominant technology for interacting with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) product without having to go through the exercise of a more complicated integration. REST APIs communicate in a common format, typically JSON. However, most will allow us to choose the response format by specifying an option in the &lsquo;Accept&rsquo; header. - Reading Json Files with Go - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ + http://localhost:1313/posts/2022-07-21-reading-json-files-with-go/ Thu, 21 Jul 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ - <p>JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting -with it, and most public APIs accept JSON in HTTP requests.</p> -<p>In this post, we&rsquo;ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the -JSON data within the file into a memory structure.</p> -<p>Let&rsquo;s assume we have the following JSON data representing an employee:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">1</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Steve&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Rogers&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Captain America&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Department&#34;</span>: <span style="color:#e6db74">&#34;Avengers&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>We need a way of representing this data in memory when decoding it from JSON. For this, we will need to create a struct:</p> -<p>We will build up our go module as we progress through the article</p> -<p>Let&rsquo;s start:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#75715e">// main.go -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> ( -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;encoding/json&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;fmt&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;io/ioutil&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;log&#34;</span> -</span></span><span style="display:flex;"><span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">// Hero represents an hero -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// ALL fields must be exportable! Otherwise the JSON parsing will fail. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Hero</span> <span style="color:#66d9ef">struct</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Id</span> <span style="color:#66d9ef">int</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">FirstName</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">LastName</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Alias</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Group</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() { -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Here we set the log prefix. When reading stack traces, this makes it easier to know -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// where a failure occurred. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">SetPrefix</span>(<span style="color:#e6db74">&#34;main(): &#34;</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// We first need to load the JSON file into memory -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">content</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">ioutil</span>.<span style="color:#a6e22e">ReadFile</span>(<span style="color:#e6db74">&#34;./heros.json&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#e6db74">&#34;Error opening the file: &#34;</span>, <span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Now we parse the JSON data into a memory structure. We know our JSON file will have more than one hero object, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// so we&#39;ll use make() to create a []Hero slice. Since go is a pass-by-value language, we will then use the address-of -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// operator (&amp;) to unmarshal our json data into the heros slice -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">heros</span> <span style="color:#f92672">:=</span> make([]<span style="color:#a6e22e">Hero</span>, <span style="color:#ae81ff">5</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">json</span>.<span style="color:#a6e22e">Unmarshal</span>(<span style="color:#a6e22e">content</span>, <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">heros</span>) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#e6db74">&#34;Error occurred during unmarshal: &#34;</span>, <span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// now we can read/interact with the data. We&#39;ll loop over the array -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// and print the values in memory -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; len(<span style="color:#a6e22e">heros</span>); <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">Id</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">FirstName</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">LastName</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">Group</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Create a file named employees.json with similar data:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>[ -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">1</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Steve&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Rogers&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Captain America&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;group&#34;</span>: <span style="color:#e6db74">&#34;Avengers&#34;</span> -</span></span><span style="display:flex;"><span> }, -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">2</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Clark&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Kent&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Superman&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;group&#34;</span>: <span style="color:#e6db74">&#34;Justice League&#34;</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>] -</span></span></code></pre></div><p>Now, we can run our main.go file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>11:40:47 ryan@xerxes json → go run main.go -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>Steve -</span></span><span style="display:flex;"><span>Rogers -</span></span><span style="display:flex;"><span>Avengers -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span>Clark -</span></span><span style="display:flex;"><span>Kent -</span></span><span style="display:flex;"><span>Justice League -</span></span><span style="display:flex;"><span>11:40:49 ryan@xerxes json -</span></span></code></pre></div><p>Pretty simple! That&rsquo;s why I love go. We accomplished all of this with ~50 lines of code. -Doing something similar in asp.net project would easily double that count and involve creating -multiple files! (nothing against asp.net or c#, I think c# is a great language and use it daily)</p> -<p>Now, &lsquo;go&rsquo; try this!</p> - + http://localhost:1313/posts/2022-07-21-reading-json-files-with-go/ + JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting with it, and most public APIs accept JSON in HTTP requests. In this post, we&rsquo;ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the JSON data within the file into a memory structure. - diff --git a/public/tags/json/page/1/index.html b/public/tags/json/page/1/index.html index 8467f3c7..d373e191 100644 --- a/public/tags/json/page/1/index.html +++ b/public/tags/json/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/json/ - + http://localhost:1313/tags/json/ + - + diff --git a/public/tags/kubernetes/index.html b/public/tags/kubernetes/index.html index b2694c65..2977ee6d 100644 --- a/public/tags/kubernetes/index.html +++ b/public/tags/kubernetes/index.html @@ -1,111 +1,77 @@ + - - - - - - - + + Tag: Kubernetes · GeekyRyan + - - -kubernetes - GeekyRyan - - + + + + - - - - - - - - - - + + + + + + + + + - - - - - - - - - - - + + + + - - + + + - - - - - + - + + + - - - - - + + + - - - + + + + - - - - - - - - - + @@ -113,813 +79,196 @@ - - - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - - -
    -
    - -

    Tag: kubernetes

    - - - -
    -
    -
    -

    Handling Graceful Shutdown in a .NET App Hosted in Kubernetes

    -
    - -
    - - -
    - I was recently involved with troubleshooting some API’s hosted in Kubernetes throwing http/502’s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. -
    - - -
    - Read more -
    - - - - - - - -
    - -
    -
    -
    -

    AKS Scale Down Mode

    -
    - -
    - - -
    - By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete or deallocate nodes. -Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Scheduled Kubernetes Worker Node Maintenance with Kured

    -
    - -
    - - -
    - If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this? -Weaveworks created a great tool for simplifying these steps: Kured (the Kubernetes Reboot Daemon). -
    - - -
    - Read more -
    - - - - - - - -
    - -
    -
    -
    -

    Running Docker in WSL v1

    -
    - -
    - - -
    - I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. -Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Remove Kubernetes Namespace Stuck in the Terminating State

    -
    - -
    - - -
    - In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state. -A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. -
    - - -
    - Read more -
    - - - - - - - -
    - -
    -
    -
    -

    Kubernetes Storage Simplified

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Tag: Kubernetes +

    +
    + +
    +
  • + 2022-01-16 + Azure Kubernetes sFTP Solution +
  • -
    -
    -
    -

    Kubernetes Pod Eviction

    -
    - -
    + + - -
    - In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation. -What is Pod Eviction? Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Azure Kubernetes sFTP Solution

    -
    -
    +
    +
    + © -
    - In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault. -Here is the link to my Github account where you can download the code mentioned in this article: -https://github.com/rnemeth90/kubernetes-sftp -We will work through the following steps in this article: -
    + 2012 - + 2024 + Ryan Nemeth + · -
    - Read more -
    - - - - + Powered by Hugo & Coder. +
    +
    +
    - + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/tags/kubernetes/index.xml b/public/tags/kubernetes/index.xml index 869cc42e..bf17d85e 100644 --- a/public/tags/kubernetes/index.xml +++ b/public/tags/kubernetes/index.xml @@ -1,766 +1,75 @@ - kubernetes on GeekyRyan - https://rnemeth90.github.io/tags/kubernetes/ - GeekyRyan (kubernetes) - Hugo -- gohugo.io - en-us - Wed, 28 Dec 2022 00:00:00 +0000 - - - - + Kubernetes on GeekyRyan + http://localhost:1313/tags/kubernetes/ + Recent content in Kubernetes on GeekyRyan + Hugo + en + Mon, 11 Dec 2023 00:00:00 +0000 + + + Nginx Ingress Response Header Size - A Cautionary Tale + http://localhost:1313/posts/2023-12-04-nginx-ingress-resp-header-size/ + Mon, 11 Dec 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-12-04-nginx-ingress-resp-header-size/ + This will be a short post about a recent issue I encountered when using Nginx as a Kubernetes ingress. Though, this could also be encountered when using Nginx as a reverse proxy as well. The two definitions are functionally similar. We recently had a client call in complaining of our application returning random 502s (Bad Gateway). After some investigation and the common finger-pointing, I found this entry in the logs of our ingress controllers: + Handling Graceful Shutdown in a .NET App Hosted in Kubernetes - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ Wed, 28 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ - <p>I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. It was actually a combination of these blogs (and the resolutions posted) that ended up resolving our issue.</p> -<h3 id="so-what-was-actually-causing-the-502s" >So what was actually causing the 502&rsquo;s? -<span> - <a href="#so-what-was-actually-causing-the-502s"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h3><p>As stated, these APIs are hosted in Kubernetes. They are written primarily in c# (.NET Framework) and hosted in Windows Server Core containers. The pods are load balanced using a service, and we have an Nginx ingress on top of the service. Nothing fancy, just a typical setup that you may have seen or even built yourself. We implement automatic scaling for our replica sets using a standard Kubernetes-native HPA or Keda, depending on the app. We have autoscale rules defined for the pods. Our clusters are hosted in Azure Kubernetes Service, and we autoscale our node pools. So, there are several layers of scaling happening in our clusters at any given time. Occasionally, when a pod was handling a client request, Kubelet or a controller would come along and scale the pod in. We were initially under the belief that the <code>terminationGracePeriodSeconds</code> value within our deployment would allow the pod to continue running for the defined number of seconds. However, we were mistaken. This value tells Kubernetes to allow the application running within the pod some time to clean up. It does <em>not</em> tell the app to continue running for the defined number of seconds after it receives a sigterm signal. This logic actually needs to be implemented within the application itself, or with a prestop hook. The prestop method is <a href="https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/">well documented</a>, so I will not cover it here.</p> -<p>To implement this in a .NET Framework app running in Windows, you need to add this registry key to your container.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">RUN</span> reg add hklm<span style="color:#ae81ff">\s</span>ystem<span style="color:#ae81ff">\c</span>urrentcontrolset<span style="color:#ae81ff">\c</span>ontrol /v WaitToKillServiceTimeout /t REG_SZ /d <span style="color:#ae81ff">60000</span> /f<span style="color:#960050;background-color:#1e0010"> -</span></span></span></code></pre></div><p>This value tells Windows to wait a number of milliseconds before shutting down Normally, Windows only waits for 5 seconds (default) before shutting down any &lsquo;background&rsquo; processes. Windows forcibly shuts down processes after this period of time.</p> -<p>Next, in the startup class, we&rsquo;ll add the following code. I have added inline comments to explain.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c#" data-lang="c#"><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">namespace</span> MyApp.APIConsoleHost -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Program</span> -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Register the SetConsoleCtrlHandler function in kernel32.dll in the -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> application to capture CTRL_SHUTDOWN_EVENT events for resource reclamation -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e"> [DllImport(&#34;Kernel32&#34;)]</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">extern</span> <span style="color:#66d9ef">bool</span> SetConsoleCtrlHandler(HandlerRoutine handler, <span style="color:#66d9ef">bool</span> <span style="color:#66d9ef">add</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Define a delegate for our handler routine</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">delegate</span> <span style="color:#66d9ef">bool</span> HandlerRoutine(CtrlTypes ctrlType); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">volatile</span> ManualResetEvent _exitEvent = <span style="color:#66d9ef">new</span> ManualResetEvent(<span style="color:#66d9ef">false</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> HandlerRoutine _handler; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Define the event types that we want to handle when the application receives a SIGTERM -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_C_EVENT = 0, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_BREAK_EVENT = 1, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_CLOSE_EVENT = 2, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_LOGOFF_EVENT = 5, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_SHUTDOWN_EVENT = 6 -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">enum</span> CtrlTypes -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> CTRL_SHUTDOWN_EVENT = <span style="color:#ae81ff">6</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Here we are defining how we want to handle the shutdown -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We get a timeout value from an env variable named APP_SHUTDOWN_TIMEOUT -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> If that env variable is not found, we default to 60 seconds. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We then switch on our CtrlTypes enum and handle each value accordingly, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then return true. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">bool</span> ConsoleCtrlCheck(CtrlTypes ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> timeout = ConfigurationManager.AppSettings[<span style="color:#e6db74">&#34;APP_SHUTDOWN_TIMEOUT&#34;</span>]; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> (<span style="color:#66d9ef">string</span>.IsNullOrEmpty(timeout)) { timeout = <span style="color:#e6db74">&#34;60&#34;</span>; } -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">int</span> counter = <span style="color:#66d9ef">int</span>.Parse(timeout); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">switch</span> (ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> CtrlTypes.CTRL_SHUTDOWN_EVENT: -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] CTRL_SHUTDOWN received&#34;</span>); -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] Web Server is stopping in {counter} seconds&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">while</span> (counter &gt; <span style="color:#ae81ff">0</span>) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> Thread.Sleep(TimeSpan.FromSeconds(<span style="color:#ae81ff">1</span>)); -</span></span><span style="display:flex;"><span> counter--; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.Set(); -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span>; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span>: -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">false</span>; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Our main method is pretty standard. However, we first register a new handler (_handler), -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then pass it to to the SetConsoleCtrlHandler() method we imported from Kernel32.dll. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> The only other &#39;unique&#39; thing is the _exitEvent.WaitOne(); call defined at the bottom of main(). -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> This is necessary so that main does not immediately exit, and wait&#39;s for a signal. We defined a -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> property for this _exitEvent of type ManualResetEvent at the top of this class file. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> Main(<span style="color:#66d9ef">string</span>[] args) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> _handler += <span style="color:#66d9ef">new</span> HandlerRoutine(ConsoleCtrlCheck); -</span></span><span style="display:flex;"><span> SetConsoleCtrlHandler(_handler, <span style="color:#66d9ef">true</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = BuildStartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> WebApp.Start&lt;SelfHostStartup&gt;(startOptions); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">&#34;Press CTRL+C to stop it&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.WaitOne(); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> StartOptions BuildStartOptions() -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = <span style="color:#66d9ef">new</span> StartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted start options</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> startOptions; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>To prevent the HandlerRoutine instance from being recycled by the GC before the program exits, the HandlerRoutine must be static (as seen in the above example). This is important because if the handlerroutine is recycled before the application is finished, it will throw an error, as shown here:</p> -<pre tabindex="0"><code>A callback was made on a garbage collected delegate of type &#39;Program+HandlerRoutine::Invoke&#39;. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called. -</code></pre> + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. - AKS Scale Down Mode - https://rnemeth90.github.io/posts/2022-07-19-aks-scale-down-mode/ + http://localhost:1313/posts/2022-07-19-aks-scale-down-mode/ Tue, 19 Jul 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-07-19-aks-scale-down-mode/ - <p>By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete <em>or</em> deallocate nodes.</p> -<p>Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. However, you will still need to pay for any storage that the node is using. Having persistent storage also means that any container images that were cached on the node will still be there when the node starts back up. This can be a major performance benefit if you are using Windows containers because the images for these containers are typically very large.</p> -<p>Scale down mode can be configured in several ways. Here, we will look at configuring it via the Azure CLI and Terraform.</p> -<p>Azure CLI:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>az aks nodepool update --scale-down-mode Deallocate --name nplinux01 --cluster-name myAKSCluster --resource-group myResourceGroup -</span></span></code></pre></div><p>Terraform:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-hcl" data-lang="hcl"><span style="display:flex;"><span><span style="color:#66d9ef">resource</span> <span style="color:#e6db74">&#34;azurerm_kubernetes_cluster_node_pool&#34; &#34;nodepool&#34;</span> { -</span></span><span style="display:flex;"><span> name <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;nplinux01&#34;</span> -</span></span><span style="display:flex;"><span> kubernetes_cluster_id <span style="color:#f92672">=</span> <span style="color:#66d9ef">azurerm_kubernetes_cluster</span>.<span style="color:#66d9ef">example</span>.<span style="color:#66d9ef">id</span> -</span></span><span style="display:flex;"><span> vm_size <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Standard_DS2_v2&#34;</span> -</span></span><span style="display:flex;"><span> node_count <span style="color:#f92672">=</span> <span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span> scale_down_mode <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Deallocate&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> tags <span style="color:#f92672">=</span> { -</span></span><span style="display:flex;"><span> Environment <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;lab&#34;</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><em>At the time of this writing, Terraform does not support configuring scale-down mode for the default AKS node pool.</em> -<em>Node pools using ephemeral disks do not support &lsquo;deallocate&rsquo; mode</em></p> - + http://localhost:1313/posts/2022-07-19-aks-scale-down-mode/ + By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete or deallocate nodes. Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. - Scheduled Kubernetes Worker Node Maintenance with Kured - https://rnemeth90.github.io/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ + http://localhost:1313/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ Fri, 15 Jul 2022 18:18:50 +0000 - - https://rnemeth90.github.io/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ - <p>If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this?</p> -<p>Weaveworks created a great tool for simplifying these steps: Kured (the <em><strong>Ku</strong>bernetes <strong>Re</strong>boot <strong>D</strong>aemon</em>). Let’s start by deploying Kured to our cluster.</p> -<p>Kured can be deployed in one of several ways. In this article, we’ll focus on deploying it via Helm. This is the simplest and quickest way to get it running in our cluster.</p> -<p>Follow these steps to install the Helm chart:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># 1) Add the Kured Helm repository</span> -</span></span><span style="display:flex;"><span>helm repo add kured https://weaveworks.github.io/kured -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 2) Update your local Helm chart repository cache</span> -</span></span><span style="display:flex;"><span>helm repo update -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 3) Create a dedicated namespace where you would like to deploy kured</span> -</span></span><span style="display:flex;"><span>kubectl create namespace kured -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 4) Install kured in that namespace with Helm 3 (only on Linux nodes)</span> -</span></span><span style="display:flex;"><span>helm install kured kured/kured --namespace kured --set nodeSelector.<span style="color:#e6db74">&#34;kubernetes\.io/os&#34;</span><span style="color:#f92672">=</span>linux -</span></span></code></pre></div><p>If all went well with the command above, that’s it, you’re done! Have a nice day! 🙂</p> -<p>If you want to test Kured, login to one of your Linux nodes, and install some patches with your package manager of choice (any patch that requires a reboot, typically patches that modify kernel headers). Then, check for a file named ‘reboot-required’ in /var/run:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>ls -lisa /var/run/reboot-required -</span></span></code></pre></div><p>If you installed patches, and this file does not exist, none of your patches require a reboot. We can still fake the system into thinking a reboot is required by manually creating the ‘reboot-required’ file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo touch /var/run/reboot-required -</span></span></code></pre></div><p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-1.png" alt=""></p> -<p>Then, we’ll use Kubetail to tail the logs of all our Kured pods:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubetail -label kured --namespace kured -</span></span></code></pre></div><p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-1024x749.png" alt=""></p> -<p>By default, Kured checks for the existence of the sentinel file every 60 minutes. However, this behavior can be changed. See the github repo for more info:</p> -<p><img src="https://github.com/weaveworks/kured#reboot-sentinel-file--period" alt="weaveworks/kured: Kubernetes Reboot Daemon"></p> -<p>Scheduling on the node should be disabled if you are within the Kured schedule</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-2.png" alt=""></p> -<p>Now that the node is cordoned off, running pods on the node are drained, and the node is rebooted.</p> -<p>That’s it for this article. Have a great day!</p> - + http://localhost:1313/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ + If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this? Weaveworks created a great tool for simplifying these steps: Kured (the Kubernetes Reboot Daemon). - Running Docker in WSL v1 - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ Sun, 26 Jun 2022 15:00:28 +0000 - - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ - <p>I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate.</p> -<p>Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. I receive this nice message:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ docker -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>The command <span style="color:#e6db74">&#39;docker&#39;</span> could not be found in this WSL <span style="color:#ae81ff">1</span> distro. -</span></span><span style="display:flex;"><span>We recommend to convert this distro to WSL <span style="color:#ae81ff">2</span> and activate -</span></span><span style="display:flex;"><span>the WSL integration in Docker Desktop settings. -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>See https://docs.docker.com/docker-for-windows/wsl/ <span style="color:#66d9ef">for</span> details. -</span></span></code></pre></div><p>So I’m in somewhat of a catch-22 here…</p> -<p>To work around this problem until a proper solution is found, I was able to get Docker working with WSL v1.</p> -<p>If you happen to be having a similar issue (and it seems like quite a few people are, considering the number of Github posts I found), just follow these steps:</p> -<ul> -<li>Expose the Docker daemon in docker desktop settings:</li> -</ul> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/02/image-10-1024x585.png"></a></p> -<p>Install the stand-alone Docker client in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ tar zxvf docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ cd docker -</span></span></code></pre></div><p>Set the default Docker daemon in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>export DOCKER_HOST<span style="color:#f92672">=</span>tcp://localhost:2375 -</span></span></code></pre></div><p>Verify you can connect to Docker running on Windows from within WSL:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>./docker info -</span></span></code></pre></div><p>This is also beneficial in that you only have one Docker host to manage your containers, network, etc., rather than two.</p> - + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ + I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. - Remove Kubernetes Namespace Stuck in the Terminating State - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ Sat, 04 Jun 2022 18:29:41 +0000 - - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ - <p>In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state.</p> -<p>A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. One day, you decide you no longer want this blog, so you plan to delete it. Rather than tediously deleting all of the various entities associated with this blog, you can delete the namespace that contains these entities. This will essentially ‘cascade delete’ the resources within the namespace as well.</p> -<p>After deleting the namespace for your blog, you notice that it still exists, but the state of it is ‘Terminating’, and it has been like this for a long time (hours or maybe even days).</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/06/image.png"></a></p> -<p>Kubernetes will occassionally fail to delete third-party resources when deleting a namespace, causing the namespace to linger. This can happen if the third-party API managing the resource is not responding to requests. To verify if any of these resources still exist, use this command:</p> -<pre tabindex="0"><code>kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get --show-kind --show-all --ignore-not-found -n &lt;terminating-namespace&gt; -</code></pre><p>If you happen to see any resources in the output, you can try force deleting them and then try to delete the namespace again.</p> -<p>In my experience, the majority of the time you will not find any resources still hanging around. Rather, the namespace will be completely empty. What is going on here?</p> -<p>Let’s take a look at the namespace:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ae81ff">$ kubectl get namespace darn-c101 -o yaml</span> -</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Namespace</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">annotations</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">kubectl.kubernetes.io/last-applied-configuration</span>: <span style="color:#ae81ff">|</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">kubernetes.io/metadata.name</span>: <span style="color:#ae81ff">darn-c101</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">finalizers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">kubernetes</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">status</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">conditions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">lastTransitionTime</span>: <span style="color:#e6db74">&#34;2022-06-01T19:05:31Z&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">message: &#39;Some content in the namespace has finalizers remaining</span>: <span style="color:#ae81ff">darn-c101.geekyryan.io/finalizer in 1 resource instances&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">reason</span>: <span style="color:#ae81ff">SomeFinalizersRemain</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">status</span>: <span style="color:#e6db74">&#34;True&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">NamespaceFinalizersRemaining</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">phase</span>: <span style="color:#ae81ff">Terminating</span> -</span></span></code></pre></div><p>Notice the inclusion of the finalizers field in the above JSON. Some namespaces have a finalizer defined under spec.</p> -<p>A finalizer is a special metadata key that tells Kubernetes to wait until a specific condition is met before it fully deletes a resource. Much like a finalizer in the .NET framework (does Java have those too? 😀 )</p> -<p>So when you run a command like <code>kubectl delete namespace &lt;namespace&gt;</code>, Kubernetes checks for a finalizer in the <code>metadata.finalizers</code> field. If the resource defined in the finalizer cannot be deleted, then the namespace is not deleted either. This puts the namespace into a perpetual terminating state and is never actually deleted.</p> -<p>When an object has been terminating for an excessive time, check its finalizers by inspecting the <code>metadata.finalizers</code> field in its YAML.</p> -<p>So we now know what the problem is. How can we solve it? Well, it’s actually quite simple. If you are using bash, use this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> -</span></span><span style="display:flex;"><span>namespaces<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>kubectl get ns --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Terminating -o jsonpath<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;{range .items[*]}{.metadata.name}{&#34;\n&#34;}{end}&#39;</span><span style="color:#66d9ef">)</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -z <span style="color:#e6db74">&#34;</span>$namespaces<span style="color:#e6db74">&#34;</span><span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">&#34;No namespaces to delete.&#34;</span> -</span></span><span style="display:flex;"><span> exit -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> namespace in $namespaces -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">do</span> -</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">&#34;[Removing Namespace]: </span>$namespace<span style="color:#e6db74">&#34;</span> -</span></span><span style="display:flex;"><span> kubectl get namespace $namespace -o json | tr -d <span style="color:#e6db74">&#34;\n&#34;</span> | sed <span style="color:#e6db74">&#34;s/\&#34;finalizers\&#34;: \[[^]]\+\]/\&#34;finalizers\&#34;: []/&#34;</span> | kubectl replace --raw /api/v1/namespaces/$namespace/finalize -f - &gt; /dev/null 2&gt;&amp;<span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">done</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span> -</span></span></code></pre></div><p><a href="https://gist.github.com/rnemeth90/e83bb4c8808f0d28412cb40edb2487d3">Delete Terminating Kubernetes Namespaces with Bash (github.com)</a></p> -<p>It will search for any namespace that is stuck in the terminating state and forcefully remove it by removing the finalizers field and then using <code> kubectl replace</code> to commit the change back to the Kube API.</p> -<p>If you prefer Powershell, you can use this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$terminatingNamespaces = kubectl get ns --field-selector=status.phase==Terminating -o jsonpath=<span style="color:#e6db74">&#34;{range .items[*]}{.metadata.name}{&#39;\n&#39;}{end}&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($ns <span style="color:#66d9ef">in</span> $terminatingNamespaces) { -</span></span><span style="display:flex;"><span> Write-Verbose <span style="color:#e6db74">&#39;[FOUND]: Forcefully removing $ns&#39;</span> -</span></span><span style="display:flex;"><span> $jsonObj = kubectl get namespace $ns -o json | ConvertFrom-Json | foreach-object { $_.spec.finalizers = @(); $_ } | -</span></span><span style="display:flex;"><span> convertto-json | kubectl replace --raw /api/v1/namespaces/$namespace/finalize <span style="color:#f92672">-f</span> - -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><a href="https://gist.github.com/rnemeth90/19d7de622a5009c1cf908c5d4deb5358">Delete Terminating Kubernetes Namespaces with Powershell (github.com)</a></p> -<p>It does the same thing as the bash script, just in more of a Window-zy way.</p> -<p>It’s that simple. I hope this was helpful. If you have any questions, comments, or concerns, please feel free to reach out.</p> - + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state. A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. - Kubernetes Storage Simplified - https://rnemeth90.github.io/posts/2022-03-01-kubernetes-storage-simplified/ + http://localhost:1313/posts/2022-03-01-kubernetes-storage-simplified/ Tue, 01 Mar 2022 08:37:58 +0000 - - https://rnemeth90.github.io/posts/2022-03-01-kubernetes-storage-simplified/ - <p>In this blog post, we will attempt to explain the current storage options that exist in Kubernetes. If you are new to Kubernetes, learning about its capabilities of managing the application state can be a daunting task.</p> -<p>Container images are built-in layers, with the runtime layer being writable. However, any files on this writable layer are only available for the container’s lifetime. We can mount a volume to a directory inside the container to have persistent data.</p> -<p>Kubernetes storage uses the concepts of volumes. Ephemeral volumes are called volumes and only last the lifetime of a pod, and “persistent volumes” are used for long-term storage. A typical use case for Ephemeral volumes is storing logs that are not sent to stdout.</p> -<p>Mounting a persistent volume inside a container allows you to persist the state of your application long after the container is terminated. Persistent volumes can also take advantage of the typical storage idiosyncrasies such as backup, compression, and encryption.</p> -<h2 id="persistent-volumes" >Persistent Volumes -<span> - <a href="#persistent-volumes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Kubernetes has several types of persistent volumes. At its core, a persistent volume is simply a directory mounted inside a pod. How that volume is created, the configuration options and the medium that backs it are all determined by the type of volume created.</p> -<p>There are several types of volumes available, too many to list here. You may commonly see some volume types: NFS, iSCSI, hostpath, and local. If your Kubernetes cluster exists in a cloud environment such as Azure or AWS, other volume types are available to you (azureDisk, azureFile, and awsElasticBlockStore, respectively). A complete list of types can be found here:</p> -<p><a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes">https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes</a></p> -<p>Creating a persistent volume is generally a simple task. The first step is determining the type of volume to create. In this post, we will cover creating a local volume. A local volume represents a disk, partition, or directory shared from a node. Local volumes are subject to the availability of the underlying node, meaning that if the node is offline, the volume is also offline and will not be accessible by any pod. Because of this, local volumes should not be used in production.</p> -<p>A persistent volume can only be created using a declarative approach. To create a persistent local volume, use the following YAML definition:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolume</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">example-pv</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">capacity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMode</span>: <span style="color:#ae81ff">Filesystem</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteOnce</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeReclaimPolicy</span>: <span style="color:#ae81ff">Delete</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">local-storage</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">local</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># the path to the volume or directory on the node</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/mnt/disks/ssd1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeAffinity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">required</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeSelectorTerms</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">matchExpressions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">key</span>: <span style="color:#ae81ff">kubernetes.io/hostname</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">operator</span>: <span style="color:#ae81ff">In</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">values</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># name of the node sharing the volume</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">node01</span> -</span></span></code></pre></div><p>When creating a persistent volume of this type, you must specify a node affinity. This ensures that the Kubernetes scheduler schedules any pods requesting access to this volume on the correct node. For example, any pod requesting access to the persistent volume named ‘example-PV will only be scheduled on the node ‘node01’.</p> -<p>Let’s dive into this persistent volume spec a bit more:</p> -<p>You can change the capacity of the persistent volume by updating:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">capacity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span></code></pre></div><p>The accessModes will be determined by the storage provider being used. There are generally 3 access modes available: ReadWriteOnce, ReadWriteMany, and ReadOnlyMany.</p> -<ul> -<li>ReadWriteOnce – The volume can be mounted as read-write by a single node</li> -<li>ReadWriteMany – The volume can be mounted as read-write by many nodes</li> -<li>ReadOnlyMany – The volume can be mounted as read-only by many nodes</li> -</ul> -<p>The “persistentVolumeReclaim” policy determines what happens to a persistent volume when it is no longer mounted by any pods (i.e., there are no claims to it, more on this later). There are three options available for the reclaim policy:</p> -<ul> -<li>Retain – The persistent volume is kept as-is. It must be manually removed when no longer needed.</li> -<li>Recycle – The persistent volume is scrubbed and can be re-used by other pods</li> -<li>Delete – The persistent volume is deleted.</li> -</ul> -<p>Currently, only NFS and hostPath volumes support recycling. Cloud storage providers (Azure, AWS, and GCE) support deletion.</p> -<p>The other aspects of this spec are unique to the volume being used. Since we are using a local volume here, we must specify the path to the directory or volume on the host and the host which is sharing the directory or volume:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span> <span style="color:#f92672">local</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># the path to the volume or directory on the node</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/mnt/disks/ssd1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeAffinity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">required</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeSelectorTerms</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">matchExpressions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">key</span>: <span style="color:#ae81ff">kubernetes.io/hostname</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">operator</span>: <span style="color:#ae81ff">In</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">values</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># name of the node sharing the volume</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">node01</span> -</span></span></code></pre></div><h2 id="ephemeral-volumes" >Ephemeral Volumes -<span> - <a href="#ephemeral-volumes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Note: The Kubernetes documentation recognizes configMaps and Secrets as ephemeral volumes. However, in this article, we will only discuss ephemeral volumes used for data storage (emptyDir volumes).</p> -<p>Ephemeral volumes are defined within the context of a pod. This means that you cannot create an ephemeral volume on its own. Instead, define the ephemeral volume in the pod or a deployment spec.</p> -<p>Ephemeral volumes are useful in a few scenarios:</p> -<ol> -<li>You want to share data between multiple containers in a pod</li> -<li>You want to cache temporary information such as log files</li> -<li>You need scratch space to store data before it is processed by another container or pod</li> -</ol> -<p>If one of the containers in the pod happens to restart, data on the ephemeral volume will still exist; as long as one of the containers is mounting, it stays online. In other words, if a pod mounting the ephemeral volume is removed from a node, data on the ephemeral volume is lost. However, if a pod crashes, the data on the volume remains intact.</p> -<p>As stated previously, creating an ephemeral volume is done as part of the pod or deployment template:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/cache</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">emptyDir</span>: {} -</span></span></code></pre></div><p>If the template, you add a volume of type ’emptyDir’ in the ‘volumes’ spec and name it. You can mount this volume in any container in the pod. The volume does not have to be mounted to the same directory in each container.</p> -<h2 id="persistent-volume-claims" >Persistent Volume Claims -<span> - <a href="#persistent-volume-claims"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>A persistentVolumeClaim (often referred to as a ‘PVC’) is used by a pod to create a ‘claim’ on storage. Using a PVC, a pod can mount multiple persistent volumes simultaneously to any directory in the pod.</p> -<p>PersistentVolumeClaim’s are a Kubernetes primitive that can be deployed from a manifest:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fast-storage-pvc</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMode</span>: <span style="color:#ae81ff">Filesystem</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">8Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">fast</span> -</span></span></code></pre></div><p>Most of the options in the manifest above seem pretty obvious. The volumeMode specifies whether to consume the persistent volume as a FileSystem or block device. The resources section helps specify the amount of storage you require (8Gi in this example). We will cover the storageClassName in the next section. Finally, the accessModes are identical to those described above in the Persistent Volumes section.</p> -<p>Pods access a volume by using the persistentVolumeClaim as volume. Claims must exist in the same namespace as the pod using the claim. The controller finds the claim in the pods’ namespace and uses it to find a persistent volume capable of backing the claim. The volume is then mounted on the host and attached to the pod.</p> -<p>To create a pod that utilizes a PVC, use the following yaml definition:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/mnt/share</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span></code></pre></div><h2 id="storage-classes" >Storage Classes -<span> - <a href="#storage-classes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>In this article, we will only be referencing Kubernetes storage classes with respect to dynamic provisioners. If you would like to learn more, please reference the Kubernetes docs:</p> -<p><a href="https://bit.ly/3ruJD2A">https://bit.ly/3ruJD2A</a></p> -<p>Storage Classes have many uses. Kubernetes is unopinionated about what a storage class represents. They can be used to represent different characteristics of storage (performance, compression method, file system modes, etc.). Storage Classes can also be used to provision persistent volumes dynamically, which will be the focus of this article.</p> -<p>Storage classes are often packaged with CSI drivers. Each StorageClass contains the fields “provisioner”, “parameters”, and “reclaimPolicy”. The provisioner field is used to determine what CSI driver is used for provisioning volumes.</p> -<p>This is an example of the storage class packaged with the AzureFiles CSI driver:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">StorageClass</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">storage.k8s.io/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azurefileshare</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">provisioner</span>: <span style="color:#ae81ff">file.csi.azure.com</span> <span style="color:#75715e"># replace with &#34;kubernetes.io/azure-file&#34; if aks version is less than 1.21</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">mountOptions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">dir_mode=0777</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">file_mode=0777</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">uid=0</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">gid=0</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">mfsymlinks</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">cache=strict</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">actimeo=30</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">parameters</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">skuName</span>: <span style="color:#ae81ff">Standard_LRS</span> -</span></span></code></pre></div><p>You can see in the above manifest that the provisioner is set to ‘file.csi.azure.com.’ When a pod uses a PVC in its manifest that references this storage class, the provisioner will dynamically manage the underlying storage.</p> -<p>The name of the storageClass is referenced in the persistentVolumeClaim:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">8Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">azurefileshare</span> -</span></span></code></pre></div><p>You could then reference this PVC in a pod:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/mnt/share</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span></code></pre></div><p>That concludes this article. I know that is a lot of information! As always, if you have any questions or comments, please reach out.</p> - + http://localhost:1313/posts/2022-03-01-kubernetes-storage-simplified/ + In this blog post, we will attempt to explain the current storage options that exist in Kubernetes. If you are new to Kubernetes, learning about its capabilities of managing the application state can be a daunting task. Container images are built-in layers, with the runtime layer being writable. However, any files on this writable layer are only available for the container’s lifetime. We can mount a volume to a directory inside the container to have persistent data. - Kubernetes Pod Eviction - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ Sat, 05 Feb 2022 23:49:16 +0000 - - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ - <p>In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation.</p> -<h2 id="what-is-pod-eviction" >What is Pod Eviction? -<span> - <a href="#what-is-pod-eviction"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. The most common of which is resource starvation on a node. This is referred to as “node-pressure eviction.”</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>NAME READY STATUS RESTARTS AGE -</span></span><span style="display:flex;"><span>nginx 0/1 Evicted <span style="color:#ae81ff">0</span> 10s -</span></span></code></pre></div><h2 id="eviction-process" >Eviction Process -<span> - <a href="#eviction-process"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The kubelet process running on the node monitors resources such as CPU, memory, disk space, inodes, etc. When one of these resources reaches a certain consumption level, the kubelet will first attempt to clean up resources by deleting non-running pods and images (in the case of storage starvation). The kubelet will then fail one or more pods on the node to reclaim resources. The class of the pod determines the order in which it does this.</p> -<p><strong>Pod Classes</strong></p> -<ul> -<li>Guaranteed: Pods that have requests and limits configured for both CPU and memory</li> -<li>Burstable: Pods with a resource request configured for memory or CPU</li> -<li>Best Effort: Pods without any requests or limits</li> -</ul> -<p>The kubelet will first evict any “best-effort” pods. If this is not enough, the kubelet will evict any “burstable” pods. Pods within the “guaranteed” class are theoretically safe from eviction.</p> -<p>During a node-pressure eviction, the kubelet sets the PodPhase for the selected pods to “Failed.” This causes the pods to terminate. If a daemonSet or replicaSet manages the pod, the Kubernetes controller-manager will create new pods on another node.</p> -<h2 id="recovery" >Recovery -<span> - <a href="#recovery"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Node-pressure eviction is almost always avoidable. We can prevent this type of issue by ensuring that we properly size our clusters and create resource limits for pods.</p> -<p><strong>Resource</strong> <strong>Requests and Limits:</strong></p> -<ul> -<li>Requests: The minimum amount of resources (CPU/memory) that a container needs to start.</li> -<li>Limits: The maximum amount of resources that a container is allowed to use.</li> -</ul> -<p>Pod resources and requests can be defined in a pod spec or deployment spec. Below is an example of a pod spec with resource requests and limits defined:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">frontend</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">nginx</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;64Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;250m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">limits</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;128Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;500m&#34;</span> -</span></span></code></pre></div><p>You will often need to clean up evicted pods manually. If you find that your cluster has a large amount of evicted pods, you can clean them up with the following kubectl commands:</p> -<p><strong>To see all failed pods in the cluster:</strong></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl get pod --all-namespaces --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Failed -</span></span></code></pre></div><p><strong>To remove all failed pods in the cluster:</strong></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl delete pod --all-namespaces --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Failed -</span></span></code></pre></div><p>I hope this article has been helpful. Please reach out if you have any questions or comments! Also, if you would like to learn more, take a look at the official Kubernetes docs:</p> -<p><a href="https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/">https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/</a></p> - + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ + In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation. What is Pod Eviction? Link to heading Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. - Azure Kubernetes sFTP Solution - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ + http://localhost:1313/posts/2022-01-16-azure-kubernetes-sftp-solution/ Sun, 16 Jan 2022 07:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-01-16-azure-kubernetes-sftp-solution/ - <p>In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault.</p> -<p>Here is the link to my Github account where you can download the code mentioned in this article:</p> -<p><a href="https://github.com/rnemeth90/kubernetes-sftp">https://github.com/rnemeth90/kubernetes-sftp</a></p> -<p>We will work through the following steps in this article:</p> -<ol> -<li>Deploy the AzureFile CSI driver to the AKS cluster</li> -<li>Create a configMap that our initContainer will</li> -<li>Deploy a persistent volume claim that an Azure File share will back</li> -<li>Deploy a replicaSet consisting of our initContainer and application container</li> -<li>Deploy a service to serve traffic</li> -</ol> -<p>First, you will need to deploy the Azure Files CSI driver to your AKS cluster. AKS uses this daemon set to dynamically provision/destroy Azure NFSv4 File Shares. The Azure Files CSI driver creates a storage account in the node pool resource group, in which it will then provision the file share.</p> -<p>Deploying the Azure Files CSI driver is a simple task. You will need to run this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/install-driver.sh | bash -s master -- -</span></span></code></pre></div><p>You can use the following commands to verify that the daemon set has exists:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl -n kube-system get pod -o wide --watch -l app<span style="color:#f92672">=</span>csi-azurefile-controller -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>kubectl -n kube-system get pod -o wide --watch -l app<span style="color:#f92672">=</span>csi-azurefile-node -</span></span></code></pre></div><figure class="wp-block-coblocks-gallery-masonry masonry-grid has-border-radius-10 has-medium-gutter"><figure class="wp-block-image size-large masonry-brick">[![Image gallery image](https://rnemeth90.github.io/wp-content/uploads/2022/01/image-1-1024x434.png)](https://rnemeth90.github.io/wp-content/uploads/2022/01/image-1.png)</figure></figure>Next, you need to create a storage class by deploying this yaml file: -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl create -f https://raw.githubusercontent.com/kubernetes-sigs/azurefile-csi-driver/master/deploy/example/storageclass-azurefile-nfs.yaml -</span></span></code></pre></div><p>Read more about the AzureFiles CSI driver at the following Github link:</p> -<p><a href="https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/install-driver-on-aks.md">https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/install-driver-on-aks.md</a></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ConfigMap</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">creationTimestamp</span>: <span style="color:#66d9ef">null</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">testcm</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">init.sh</span>: |-<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> #!/bin/bash -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> CONF_FILE=&#34;/etc/sftp/users.conf&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> KEYVAULT=&#34;Insert name of Key Vault&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_ID=&#34;Insert service principal Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_PASSWORD=&#34;Insert service principal password&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SPN_TENANT_ID=&#34;Insert Az AAD Tenant Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> AZ_SUBSCRIPTION_ID=&#34;Insert Az Subscription Id&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az login --service-principal --username &#34;${AZ_SPN_ID}&#34; --password &#34;${AZ_SPN_PASSWORD}&#34; --tenant &#34;${AZ_SPN_TENANT_ID}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> az account set --subscription &#34;${AZ_SUBSCRIPTION_ID}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETS+=($(az keyvault secret list --vault-name $KEYVAULT --query &#34;[].id&#34; -o tsv)) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> chmod 755 /home -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [[ -e $CONF_FILE ]]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> rm -rf &#34;${CONF_FILE}&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> touch $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> else -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> touch $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> for SECRET in &#34;${SECRETS[@]}&#34;; do -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETNAME=$(basename $SECRET | tr -d &#39;\r&#39;) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> SECRETVALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $SECRETNAME --query &#39;value&#39; | tr -d &#39;&#34;&#39; | tr -d &#39;\r&#39;) -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;$SECRETNAME:$SECRETVALUE:::upload&#34; &gt;&gt; $CONF_FILE -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> done -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> if [[ ! -s $CONF_FILE ]]; then -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo &#34;** ERROR: user.conf is empty&#34; 1&gt;&amp;2 -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> exit 1 -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> fi</span> -</span></span></code></pre></div><p>The initContainer will use this configMap to read secrets from an Azure Key Vault and then write the secrets to the users.conf file. The users.conf file contains user account information. In the Key Vault, the secret name should be the username and the secret value should be the password. This Key Vault must exist and contain the secrets prior to deploying this solution.</p> -<p>When I deployed this solution in my environment, I used an Azure DevOps pipeline to create/manage the Key Vault with Terraform and then deploy the secrets using an inline Powershell script. However, this is beyond the scope of this article, and I will not be covering it here. You will also need to create a Service Principal in your AAD tenant and grant it access to the Key Vault. The Service Principal needs to have at least read access to the Key Vault.</p> -<p>Before deploying the configMap, you need to fill in values for these variables:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span> KEYVAULT<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert name of Key Vault&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert service principal Id&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_PASSWORD<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert service principal password&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SPN_TENANT_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert Az AAD Tenant Id&#34;</span> -</span></span><span style="display:flex;"><span> AZ_SUBSCRIPTION_ID<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Insert Az Subscription Id&#34;</span> -</span></span></code></pre></div><p>These values pertain to the service principal with read access to the Key Vault. After filling out these variables, you can deploy the configMap using kubectl.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl create -f configmap.yaml -</span></span></code></pre></div><p>You can deploy the PVC using this yaml file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">azurefile-csi-nfs</span> -</span></span></code></pre></div><p>When creating the persistent volume claim for the deployment, you specify azurefile-csi-nfs as the StorageClass. This will create an NFSv4 share in a premium storage account. The reclaim policy of the storage class ensures that the file share is deleted when the associated Persistent Volume is deleted. Change the reclaim policy to “Retain” if you want the file shares to persist after deleting the PV. Furthermore, the storage class enables the file share to be expandable by modifying the storage request size on the PVC.</p> -<p>After deploying the PVC, you can verify its existence by running:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl get pvc -</span></span></code></pre></div><p>You should see output similar to the following (the manifest for the replicaSet is by far the most complicated of all the code referenced here):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">apps/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Deployment</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">matchLabels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">strategy</span>: {} -</span></span><span style="display:flex;"><span> <span style="color:#f92672">template</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initContainer</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">chmodder</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">mcr.microsoft.com/azure-cli</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">command</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">/bin/sh</span> -</span></span><span style="display:flex;"><span> - -<span style="color:#ae81ff">c</span> -</span></span><span style="display:flex;"><span> - <span style="color:#e6db74">&#34;/scripts/init.sh&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/scripts</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">docker.io/atmoz/sftp:alpine</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">imagePullPolicy</span>: <span style="color:#ae81ff">IfNotPresent</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;64Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;250m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">limits</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;128Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;500m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">livenessProbe</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tcpSocket</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initialDelaySeconds</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">timeoutSeconds</span>: <span style="color:#ae81ff">5</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">periodSeconds</span>: <span style="color:#ae81ff">10</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">failureThreshold</span>: <span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">readinessProbe</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">tcpSocket</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">initialDelaySeconds</span>: <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">timeoutSeconds</span>: <span style="color:#ae81ff">5</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">periodSeconds</span>: <span style="color:#ae81ff">10</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">failureThreshold</span>: <span style="color:#ae81ff">3</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/home</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/etc/sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">dnsPolicy</span>: <span style="color:#ae81ff">ClusterFirst</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">restartPolicy</span>: <span style="color:#ae81ff">Never</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">pvc-ftp-clientdirs</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">configMap</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">init-shell-script</span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">emptyDir</span>: {} -</span></span></code></pre></div><p>You may need to change the CPU/memory requests and limits. These values worked for me, but your results may vary. You can also add/change the labels as you see fit.</p> -<p>This will handle routing traffic to our pods.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Service</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">sftp-service</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">app</span>: <span style="color:#ae81ff">sftp</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">LoadBalancer</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">ports</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">protocol</span>: <span style="color:#ae81ff">TCP</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">22</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">targetPort</span>: <span style="color:#ae81ff">22</span> -</span></span></code></pre></div><p>Users will be connected in a round-robin fashion to the pods. This manifest will create a service of type LoadBalancer. Which will in turn create a new public Azure Load Balancer in the resource group that contains your Azure Kubernetes Service cluster if one does not already exist. If you already have a public load balancer, a new frontend IP address will be added.</p> -<p>That’s all for now. Please feel free to contact me if you have any questions.</p> - + http://localhost:1313/posts/2022-01-16-azure-kubernetes-sftp-solution/ + In this post, we’ll take a look at deploying a highly available sFTP solution to Azure Kubernetes with user files stored in an Azure NFSv4 File Share. The sFTP application reads user credentials from a file named users.conf, containing secrets from an Azure Key Vault. Here is the link to my Github account where you can download the code mentioned in this article: https://github.com/rnemeth90/kubernetes-sftp We will work through the following steps in this article: - diff --git a/public/tags/kubernetes/page/1/index.html b/public/tags/kubernetes/page/1/index.html index d3472214..dde5e492 100644 --- a/public/tags/kubernetes/page/1/index.html +++ b/public/tags/kubernetes/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/kubernetes/ - + http://localhost:1313/tags/kubernetes/ + - + diff --git a/public/tags/linux/index.html b/public/tags/linux/index.html index 3fe67606..4ef06477 100644 --- a/public/tags/linux/index.html +++ b/public/tags/linux/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Linux · GeekyRyan + - - -Linux - GeekyRyan - - - - - + - - - - + + + - - - - - + + + + + + + + + - - - - - - - - - + + + + - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,641 +79,191 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - -
    -
    - -

    Tag: Linux

    - - - -
    -
    -
    -

    Scheduled Kubernetes Worker Node Maintenance with Kured

    -
    - -
    - - -
    - If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this? -Weaveworks created a great tool for simplifying these steps: Kured (the Kubernetes Reboot Daemon). -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Running Docker in WSL v1

    -
    - -
    - - -
    - I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. -Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. -
    - - -
    - Read more -
    - - - - - - -
    - -
    -
    -
    -

    Remove Kubernetes Namespace Stuck in the Terminating State

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Tag: Linux +

    +
    + +
    +
  • + 2015-03-09 + Ping Sweeping with FPing +
  • -
    -
    -
    -

    Azure VM Scale Set &#8211; Get Instance IP Address

    -
    - -
    + + - -
    - If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal. -There are a few options we have for retrieving information about a VMSS and its instances without using the Azure Portal. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Reset GRUB/root Password for vCenter/PSC Appliance

    -
    -
    +
    +
    + © -
    - In Redhat/Fedora/Cent, GRUB can be protected by running the grub-md5-crypt command and pasting the outputted password hash into the grub.conf file. vSphere 6.0 password protects grub by default. If you change the root password in the VAMI, the GRUB password is changed to match. If you do not change the root password, the GRUB password is “vmware”. -To reset the GRUB password, we need to boot into a Cent or Redhat live CD. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - - - - -
    - -
    -
    -
    -

    Ping Sweeping with FPing

    -
    - -
    - - -
    - I generally use NMAP for any type of host discovery, but recently started experimenting with FPing. One thing I found is that, when performing a ping sweep, not only do I see the hosts that replied to the ping, but FPing also sends any unreachable IP addresses to stdout (which is super annoying and ugly if you ask me…). -Anyway, after a bit of research, I found a nifty way to suppress these messages. -
    - - -
    - Read more -
    - - - - - - + + -
    - https://rnemeth90.github.io/posts/2015-03-09-ping-sweeping-with-fping/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/linux/index.xml b/public/tags/linux/index.xml index 2e711357..f0a0726b 100644 --- a/public/tags/linux/index.xml +++ b/public/tags/linux/index.xml @@ -2,220 +2,67 @@ Linux on GeekyRyan - https://rnemeth90.github.io/tags/linux/ - GeekyRyan (Linux) - Hugo -- gohugo.io - en-us - Fri, 15 Jul 2022 18:18:50 +0000 - - - - + http://localhost:1313/tags/linux/ + Recent content in Linux on GeekyRyan + Hugo + en + Mon, 11 Dec 2023 00:00:00 +0000 + + + Nginx Ingress Response Header Size - A Cautionary Tale + http://localhost:1313/posts/2023-12-04-nginx-ingress-resp-header-size/ + Mon, 11 Dec 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-12-04-nginx-ingress-resp-header-size/ + This will be a short post about a recent issue I encountered when using Nginx as a Kubernetes ingress. Though, this could also be encountered when using Nginx as a reverse proxy as well. The two definitions are functionally similar. We recently had a client call in complaining of our application returning random 502s (Bad Gateway). After some investigation and the common finger-pointing, I found this entry in the logs of our ingress controllers: + + + Exploring Netcat + http://localhost:1313/posts/2023-11-27-netcat/ + Mon, 27 Nov 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-11-27-netcat/ + Introduction Link to heading Netcat is a versatile networking utility that can be used for a wide range of tasks. It has often been referred to as the &ldquo;network swiss-army knife&rdquo;. Netcat was first released in the mid-90s, and I personally find it ironic to be blogging about it in 2023! But I feel like it is a somewhat cryptic tool, and new engineers or college graduates may not be familiar. + Scheduled Kubernetes Worker Node Maintenance with Kured - https://rnemeth90.github.io/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ + http://localhost:1313/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ Fri, 15 Jul 2022 18:18:50 +0000 - - https://rnemeth90.github.io/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ - <p>If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this?</p> -<p>Weaveworks created a great tool for simplifying these steps: Kured (the <em><strong>Ku</strong>bernetes <strong>Re</strong>boot <strong>D</strong>aemon</em>). Let’s start by deploying Kured to our cluster.</p> -<p>Kured can be deployed in one of several ways. In this article, we’ll focus on deploying it via Helm. This is the simplest and quickest way to get it running in our cluster.</p> -<p>Follow these steps to install the Helm chart:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e"># 1) Add the Kured Helm repository</span> -</span></span><span style="display:flex;"><span>helm repo add kured https://weaveworks.github.io/kured -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 2) Update your local Helm chart repository cache</span> -</span></span><span style="display:flex;"><span>helm repo update -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 3) Create a dedicated namespace where you would like to deploy kured</span> -</span></span><span style="display:flex;"><span>kubectl create namespace kured -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># 4) Install kured in that namespace with Helm 3 (only on Linux nodes)</span> -</span></span><span style="display:flex;"><span>helm install kured kured/kured --namespace kured --set nodeSelector.<span style="color:#e6db74">&#34;kubernetes\.io/os&#34;</span><span style="color:#f92672">=</span>linux -</span></span></code></pre></div><p>If all went well with the command above, that’s it, you’re done! Have a nice day! 🙂</p> -<p>If you want to test Kured, login to one of your Linux nodes, and install some patches with your package manager of choice (any patch that requires a reboot, typically patches that modify kernel headers). Then, check for a file named ‘reboot-required’ in /var/run:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>ls -lisa /var/run/reboot-required -</span></span></code></pre></div><p>If you installed patches, and this file does not exist, none of your patches require a reboot. We can still fake the system into thinking a reboot is required by manually creating the ‘reboot-required’ file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>sudo touch /var/run/reboot-required -</span></span></code></pre></div><p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-1.png" alt=""></p> -<p>Then, we’ll use Kubetail to tail the logs of all our Kured pods:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubetail -label kured --namespace kured -</span></span></code></pre></div><p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-1024x749.png" alt=""></p> -<p>By default, Kured checks for the existence of the sentinel file every 60 minutes. However, this behavior can be changed. See the github repo for more info:</p> -<p><img src="https://github.com/weaveworks/kured#reboot-sentinel-file--period" alt="weaveworks/kured: Kubernetes Reboot Daemon"></p> -<p>Scheduling on the node should be disabled if you are within the Kured schedule</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/07/image-2.png" alt=""></p> -<p>Now that the node is cordoned off, running pods on the node are drained, and the node is rebooted.</p> -<p>That’s it for this article. Have a great day!</p> - + http://localhost:1313/posts/2022-07-15-scheduled-kubernetes-worker-node-maintenance-with-kured/ + If you manage Linux nodes, you know how vital performing regular maintenance is. Installing software patches that modify Linux kernel headers requires a reboot. Normally, as in the past, we would cordon and drain the node and then manually reboot, wait for it to come back online, verify its health, and add it back to the cluster. That’s a lot of manual work! How can we automate this? Weaveworks created a great tool for simplifying these steps: Kured (the Kubernetes Reboot Daemon). - Running Docker in WSL v1 - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ Sun, 26 Jun 2022 15:00:28 +0000 - - https://rnemeth90.github.io/posts/2022-06-26-running-docker-in-wsl-v1/ - <p>I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate.</p> -<p>Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. I receive this nice message:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ docker -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>The command <span style="color:#e6db74">&#39;docker&#39;</span> could not be found in this WSL <span style="color:#ae81ff">1</span> distro. -</span></span><span style="display:flex;"><span>We recommend to convert this distro to WSL <span style="color:#ae81ff">2</span> and activate -</span></span><span style="display:flex;"><span>the WSL integration in Docker Desktop settings. -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>See https://docs.docker.com/docker-for-windows/wsl/ <span style="color:#66d9ef">for</span> details. -</span></span></code></pre></div><p>So I’m in somewhat of a catch-22 here…</p> -<p>To work around this problem until a proper solution is found, I was able to get Docker working with WSL v1.</p> -<p>If you happen to be having a similar issue (and it seems like quite a few people are, considering the number of Github posts I found), just follow these steps:</p> -<ul> -<li>Expose the Docker daemon in docker desktop settings:</li> -</ul> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2022/02/image-10-1024x585.png"></a></p> -<p>Install the stand-alone Docker client in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ tar zxvf docker-20.10.5.tgz -</span></span><span style="display:flex;"><span>$ cd docker -</span></span></code></pre></div><p>Set the default Docker daemon in WSL v1:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>export DOCKER_HOST<span style="color:#f92672">=</span>tcp://localhost:2375 -</span></span></code></pre></div><p>Verify you can connect to Docker running on Windows from within WSL:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>./docker info -</span></span></code></pre></div><p>This is also beneficial in that you only have one Docker host to manage your containers, network, etc., rather than two.</p> - + http://localhost:1313/posts/2022-06-26-running-docker-in-wsl-v1/ + I have somewhat of a niche issue, where I have no network connectivity while connecting to my work VPN inside of WSL v2. I have found others complaining about this issue on Github. Though no one seems to know how to fix it and I have not had the time to properly investigate. Because of this, I’m required to continue using WSL v1. Though, with WSL v1, Docker does not work. - Remove Kubernetes Namespace Stuck in the Terminating State - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ Sat, 04 Jun 2022 18:29:41 +0000 - - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ - <p>In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state.</p> -<p>A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. One day, you decide you no longer want this blog, so you plan to delete it. Rather than tediously deleting all of the various entities associated with this blog, you can delete the namespace that contains these entities. This will essentially ‘cascade delete’ the resources within the namespace as well.</p> -<p>After deleting the namespace for your blog, you notice that it still exists, but the state of it is ‘Terminating’, and it has been like this for a long time (hours or maybe even days).</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/06/image.png"></a></p> -<p>Kubernetes will occassionally fail to delete third-party resources when deleting a namespace, causing the namespace to linger. This can happen if the third-party API managing the resource is not responding to requests. To verify if any of these resources still exist, use this command:</p> -<pre tabindex="0"><code>kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get --show-kind --show-all --ignore-not-found -n &lt;terminating-namespace&gt; -</code></pre><p>If you happen to see any resources in the output, you can try force deleting them and then try to delete the namespace again.</p> -<p>In my experience, the majority of the time you will not find any resources still hanging around. Rather, the namespace will be completely empty. What is going on here?</p> -<p>Let’s take a look at the namespace:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ae81ff">$ kubectl get namespace darn-c101 -o yaml</span> -</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Namespace</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">annotations</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">kubectl.kubernetes.io/last-applied-configuration</span>: <span style="color:#ae81ff">|</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">kubernetes.io/metadata.name</span>: <span style="color:#ae81ff">darn-c101</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">finalizers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">kubernetes</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">status</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">conditions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">lastTransitionTime</span>: <span style="color:#e6db74">&#34;2022-06-01T19:05:31Z&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">message: &#39;Some content in the namespace has finalizers remaining</span>: <span style="color:#ae81ff">darn-c101.geekyryan.io/finalizer in 1 resource instances&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">reason</span>: <span style="color:#ae81ff">SomeFinalizersRemain</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">status</span>: <span style="color:#e6db74">&#34;True&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">NamespaceFinalizersRemaining</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">phase</span>: <span style="color:#ae81ff">Terminating</span> -</span></span></code></pre></div><p>Notice the inclusion of the finalizers field in the above JSON. Some namespaces have a finalizer defined under spec.</p> -<p>A finalizer is a special metadata key that tells Kubernetes to wait until a specific condition is met before it fully deletes a resource. Much like a finalizer in the .NET framework (does Java have those too? 😀 )</p> -<p>So when you run a command like <code>kubectl delete namespace &lt;namespace&gt;</code>, Kubernetes checks for a finalizer in the <code>metadata.finalizers</code> field. If the resource defined in the finalizer cannot be deleted, then the namespace is not deleted either. This puts the namespace into a perpetual terminating state and is never actually deleted.</p> -<p>When an object has been terminating for an excessive time, check its finalizers by inspecting the <code>metadata.finalizers</code> field in its YAML.</p> -<p>So we now know what the problem is. How can we solve it? Well, it’s actually quite simple. If you are using bash, use this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> -</span></span><span style="display:flex;"><span>namespaces<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>kubectl get ns --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Terminating -o jsonpath<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;{range .items[*]}{.metadata.name}{&#34;\n&#34;}{end}&#39;</span><span style="color:#66d9ef">)</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -z <span style="color:#e6db74">&#34;</span>$namespaces<span style="color:#e6db74">&#34;</span><span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">&#34;No namespaces to delete.&#34;</span> -</span></span><span style="display:flex;"><span> exit -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> namespace in $namespaces -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">do</span> -</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">&#34;[Removing Namespace]: </span>$namespace<span style="color:#e6db74">&#34;</span> -</span></span><span style="display:flex;"><span> kubectl get namespace $namespace -o json | tr -d <span style="color:#e6db74">&#34;\n&#34;</span> | sed <span style="color:#e6db74">&#34;s/\&#34;finalizers\&#34;: \[[^]]\+\]/\&#34;finalizers\&#34;: []/&#34;</span> | kubectl replace --raw /api/v1/namespaces/$namespace/finalize -f - &gt; /dev/null 2&gt;&amp;<span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">done</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span> -</span></span></code></pre></div><p><a href="https://gist.github.com/rnemeth90/e83bb4c8808f0d28412cb40edb2487d3">Delete Terminating Kubernetes Namespaces with Bash (github.com)</a></p> -<p>It will search for any namespace that is stuck in the terminating state and forcefully remove it by removing the finalizers field and then using <code> kubectl replace</code> to commit the change back to the Kube API.</p> -<p>If you prefer Powershell, you can use this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$terminatingNamespaces = kubectl get ns --field-selector=status.phase==Terminating -o jsonpath=<span style="color:#e6db74">&#34;{range .items[*]}{.metadata.name}{&#39;\n&#39;}{end}&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($ns <span style="color:#66d9ef">in</span> $terminatingNamespaces) { -</span></span><span style="display:flex;"><span> Write-Verbose <span style="color:#e6db74">&#39;[FOUND]: Forcefully removing $ns&#39;</span> -</span></span><span style="display:flex;"><span> $jsonObj = kubectl get namespace $ns -o json | ConvertFrom-Json | foreach-object { $_.spec.finalizers = @(); $_ } | -</span></span><span style="display:flex;"><span> convertto-json | kubectl replace --raw /api/v1/namespaces/$namespace/finalize <span style="color:#f92672">-f</span> - -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><a href="https://gist.github.com/rnemeth90/19d7de622a5009c1cf908c5d4deb5358">Delete Terminating Kubernetes Namespaces with Powershell (github.com)</a></p> -<p>It does the same thing as the bash script, just in more of a Window-zy way.</p> -<p>It’s that simple. I hope this was helpful. If you have any questions, comments, or concerns, please feel free to reach out.</p> - + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state. A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. - Azure VM Scale Set &#8211; Get Instance IP Address - https://rnemeth90.github.io/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ + http://localhost:1313/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ Thu, 19 Nov 2020 18:07:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ - <p>If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal.</p> -<p>There are a few options we have for retrieving information about a VMSS and its instances without using the Azure Portal. We can use PowerShell or the Azure CLI. Being that I am constantly flipping between Windows and Linux, I will detail both here.</p> -<p>You will need to have the AZ module installed. To install this module, simple open PowerShell (as admin) and type in “Install-Module -Name az”. To get the IP address of the instances within a scale set, use the following script:</p> -<p><a href="https://github.com/rnemeth90/Get-VmssInstanceIpAddress">https://github.com/rnemeth90/Get-VmssInstanceIpAddress</a></p> -<p>You can also use the Azure CLI to obtain individual instance IP addresses. This method is much simpler than PowerShell, and only requires one line of code:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>az vmss nic list –resource-group myResourceGroup –vmss-name myVmss | grep –w “privateIpAddress” -</span></span></code></pre></div> + http://localhost:1313/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ + If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal. There are a few options we have for retrieving information about a VMSS and its instances without using the Azure Portal. - Reset GRUB/root Password for vCenter/PSC Appliance - https://rnemeth90.github.io/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ + http://localhost:1313/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ Sat, 31 Oct 2020 01:22:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ - <p>In Redhat/Fedora/Cent, GRUB can be protected by running the grub-md5-crypt command and pasting the outputted password hash into the grub.conf file. vSphere 6.0 password protects grub by default. If you change the root password in the VAMI, the GRUB password is changed to match. If you do not change the root password, the GRUB password is “vmware”.</p> -<p>To reset the GRUB password, we need to boot into a Cent or Redhat live CD. The ISO can be obtained here: <a href="https://www.centos.org/download/">https://www.centos.org/download/</a>. Its best to upload the ISO to a datastore that the appliance has access to.</p> -<p>Stop the appliance and attach the ISO:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image.png" alt=""></p> -<p>Be sure to select the “Connect at Power On” option. Boot the VM into the ISO and select the “Troubleshooting” option.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-1.png" alt=""> -Next, choose “Rescure a Red hat (or CentOS depending on your ISO) Enterprise Linux System”</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-2.png" alt=""></p> -<p>Select “Continue” to mount the VCSA 6.0’s root filesystem in Read/write mode under /mnt/sysimage. RHEL 7.2 is capable to detect the VCSA’s root volume and mounts it.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-3.png" alt=""></p> -<p>The VCSA root filesystem is mounted under /mnt/sysimage and you can now access (and modify) it using the shell. Navigate to /mnt/sysimage/boot and list the contents. You’ll see we now have access to the grub directory:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-4.png" alt=""></p> -<p>cd to the grub directory and list the contents. Look for a file called “menu.lst”. This file holds the grub boot loader password. Open this file with vi by typing “vi menu.lst”. Navigate to the line beginning with “password” using the arrow keys, and then type “dd” to remove the line.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-5.png" alt=""> -You can then save the file by pressing “:wq” (without quotes). You can now cat the file and see that the password has been removed.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-6.png" alt=""></p> -<p>Exit the shell (this will reboot the server). Detach the ISO and boot the appliance. Once the system is booted, stop the VCSA in the GRUB menu (by pressing the escape key during boot) to break the OS root password.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-7.png"></a> -Press “e” to edit the boot commands for the kernel.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-8.png" alt=""></p> -<p>Append “init=/bin/bash” to the line in this step and press enter.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-9.png" alt=""></p> -<p>Press “b” to boot the system.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-10.png" alt=""></p> -<p>You will now boot into a bash shell where you can set the root password.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-11.png" alt=""></p> -<p>Once this is done, exit the shell by typing “exit”. You can now boot the appliance and login with your new root password.</p> - + http://localhost:1313/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ + In Redhat/Fedora/Cent, GRUB can be protected by running the grub-md5-crypt command and pasting the outputted password hash into the grub.conf file. vSphere 6.0 password protects grub by default. If you change the root password in the VAMI, the GRUB password is changed to match. If you do not change the root password, the GRUB password is “vmware”. To reset the GRUB password, we need to boot into a Cent or Redhat live CD. - Ping Sweeping with FPing - https://rnemeth90.github.io/posts/2015-03-09-ping-sweeping-with-fping/ + http://localhost:1313/posts/2015-03-09-ping-sweeping-with-fping/ Mon, 09 Mar 2015 01:08:00 +0000 - - https://rnemeth90.github.io/posts/2015-03-09-ping-sweeping-with-fping/ - <p>I generally use NMAP for any type of host discovery, but recently started experimenting with FPing. One thing I found is that, when performing a ping sweep, not only do I see the hosts that replied to the ping, but FPing also sends any unreachable IP addresses to stdout (which is super annoying and ugly if you ask me…).</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h04_50.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h04_50.png" alt=""></a></p> -<p>Anyway, after a bit of research, I found a nifty way to suppress these messages. Linux allows us to redirect all error messages to /dev/null. So instead of just running the vanilla fping -a -g…. you would run the program and output all error messages /dev/null, like so:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h07_14.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h07_14.png" alt=""></a></p> - + http://localhost:1313/posts/2015-03-09-ping-sweeping-with-fping/ + I generally use NMAP for any type of host discovery, but recently started experimenting with FPing. One thing I found is that, when performing a ping sweep, not only do I see the hosts that replied to the ping, but FPing also sends any unreachable IP addresses to stdout (which is super annoying and ugly if you ask me…). Anyway, after a bit of research, I found a nifty way to suppress these messages. - diff --git a/public/tags/linux/page/1/index.html b/public/tags/linux/page/1/index.html index 8a72b804..62bad166 100644 --- a/public/tags/linux/page/1/index.html +++ b/public/tags/linux/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/linux/ - + http://localhost:1313/tags/linux/ + - + diff --git a/public/tags/netcat/index.html b/public/tags/netcat/index.html new file mode 100644 index 00000000..73280492 --- /dev/null +++ b/public/tags/netcat/index.html @@ -0,0 +1,234 @@ + + + + + Tag: Netcat · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    +
    +

    + Tag: Netcat +

    +
    + + + + + + + + + +
    + + +
    + +
    +
    + © + + 2012 - + + 2024 + Ryan Nemeth + · + + Powered by Hugo & Coder. + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/tags/netcat/index.xml b/public/tags/netcat/index.xml new file mode 100644 index 00000000..0c8bdece --- /dev/null +++ b/public/tags/netcat/index.xml @@ -0,0 +1,19 @@ + + + + Netcat on GeekyRyan + http://localhost:1313/tags/netcat/ + Recent content in Netcat on GeekyRyan + Hugo + en + Mon, 27 Nov 2023 00:00:00 +0000 + + + Exploring Netcat + http://localhost:1313/posts/2023-11-27-netcat/ + Mon, 27 Nov 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-11-27-netcat/ + Introduction Link to heading Netcat is a versatile networking utility that can be used for a wide range of tasks. It has often been referred to as the &ldquo;network swiss-army knife&rdquo;. Netcat was first released in the mid-90s, and I personally find it ironic to be blogging about it in 2023! But I feel like it is a somewhat cryptic tool, and new engineers or college graduates may not be familiar. + + + diff --git a/public/tags/netcat/page/1/index.html b/public/tags/netcat/page/1/index.html new file mode 100644 index 00000000..6c6f377f --- /dev/null +++ b/public/tags/netcat/page/1/index.html @@ -0,0 +1,10 @@ + + + + http://localhost:1313/tags/netcat/ + + + + + + diff --git a/public/tags/networking/index.html b/public/tags/networking/index.html index cdb6cd23..11f8c173 100644 --- a/public/tags/networking/index.html +++ b/public/tags/networking/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Networking · GeekyRyan + - - -Networking - GeekyRyan + - + + + - - - + + + - + + + + + + - - - + + + + - - - - - - - - - - - - - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,526 +79,181 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - - -
    -
    - -

    Tag: Networking

    - - - -
    -
    -
    -

    Azure VM Scale Set &#8211; Get Instance IP Address

    -
    - -
    - - -
    - If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal. -There are a few options we have for retrieving information about a VMSS and its instances without using the Azure Portal. -
    - - -
    - Read more -
    - - - - - - - - -
    - -
    -
    -
    -

    Cisco AnyConnect &#8211; VPN Establishment Capability from a Remote Desktop is Disabled

    -
    - -
    - -
    - I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution. -Upon installation, AnyConnect pulls down a profile from the ASA containing several settings. This profile is in xml format and is located (on a Windows machine) at %programdata%CiscoCisco AnyConnect Secure Mobility ClientProfileAnyConnectProfile.xsd. -To resolve this issue and connect to your VPN, open this file with notepad (or any text editor, run as admin), search for the “WindowsVPNEstablishment” tag, and modify the value. -
    - - -
    - Read more -
    - - - - -
    - -
    -
    -
    -

    DHCP Address Negotiation Process

    -
    - -
    +
    + + + + - -
    - -
    -
    -
    -

    TCP/IP Network Fundamentals

    -
    - -
    - -
    - Going over the basics of network fundamentals and all the models and ideas behind them. The most pushed idea is the OSI networking model which consists of 7 layers, all of which deal with a certain aspect of the networking model. -A P S T N D P -From the top down this represents the following -Layer 7: Application – This layer is the channel between software and external requests. For example, a web server would work with this layer to process HTTP requests. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Layer 2 Switching Fundamentals

    -
    - -
    - - -
    - Switches are devices that support a large number of ports to connect devices to the network. -Design: More towards a CCNP or CCDA topic, but designing a network when it comes to the switching side can be done in three building blocks. The access layer, the distribution layer, and the core layer. The access layer generally has a high port density, can support VLANs, QoS, and access lists. The distribution layer will aggregate multiple access layer switches. -
    +
    +
    + © + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - +
    +
    -
    - https://rnemeth90.github.io/posts/2012-11-16-layer-2-switching-fundamentals/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/networking/index.xml b/public/tags/networking/index.xml index 4fdd4ba5..a2c2e139 100644 --- a/public/tags/networking/index.xml +++ b/public/tags/networking/index.xml @@ -2,120 +2,53 @@ Networking on GeekyRyan - https://rnemeth90.github.io/tags/networking/ - GeekyRyan (Networking) - Hugo -- gohugo.io - en-us - Thu, 19 Nov 2020 18:07:00 +0000 - - - - + http://localhost:1313/tags/networking/ + Recent content in Networking on GeekyRyan + Hugo + en + Mon, 27 Nov 2023 00:00:00 +0000 + + + Exploring Netcat + http://localhost:1313/posts/2023-11-27-netcat/ + Mon, 27 Nov 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-11-27-netcat/ + Introduction Link to heading Netcat is a versatile networking utility that can be used for a wide range of tasks. It has often been referred to as the &ldquo;network swiss-army knife&rdquo;. Netcat was first released in the mid-90s, and I personally find it ironic to be blogging about it in 2023! But I feel like it is a somewhat cryptic tool, and new engineers or college graduates may not be familiar. + Azure VM Scale Set &#8211; Get Instance IP Address - https://rnemeth90.github.io/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ + http://localhost:1313/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ Thu, 19 Nov 2020 18:07:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ - <p>If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal.</p> -<p>There are a few options we have for retrieving information about a VMSS and its instances without using the Azure Portal. We can use PowerShell or the Azure CLI. Being that I am constantly flipping between Windows and Linux, I will detail both here.</p> -<p>You will need to have the AZ module installed. To install this module, simple open PowerShell (as admin) and type in “Install-Module -Name az”. To get the IP address of the instances within a scale set, use the following script:</p> -<p><a href="https://github.com/rnemeth90/Get-VmssInstanceIpAddress">https://github.com/rnemeth90/Get-VmssInstanceIpAddress</a></p> -<p>You can also use the Azure CLI to obtain individual instance IP addresses. This method is much simpler than PowerShell, and only requires one line of code:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>az vmss nic list –resource-group myResourceGroup –vmss-name myVmss | grep –w “privateIpAddress” -</span></span></code></pre></div> + http://localhost:1313/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ + If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal. There are a few options we have for retrieving information about a VMSS and its instances without using the Azure Portal. - Cisco AnyConnect &#8211; VPN Establishment Capability from a Remote Desktop is Disabled - https://rnemeth90.github.io/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ + http://localhost:1313/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ Wed, 07 Oct 2020 13:28:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ - <p>I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution.</p> -<p><a href="https://lh3.googleusercontent.com/-BYApW8vZjV8/X33B2Or4D7I/AAAAAAAAxuY/hWQwpE-fqo4xInAsx9vyUvzDJXqxe68QQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-16.png" alt=""></a></p> -<p>Upon installation, AnyConnect pulls down a profile from the ASA containing several settings. This profile is in xml format and is located (on a Windows machine) at %programdata%CiscoCisco AnyConnect Secure Mobility ClientProfileAnyConnectProfile.xsd.</p> -<p>To resolve this issue and connect to your VPN, open this file with notepad (or any text editor, run as admin), search for the “WindowsVPNEstablishment” tag, and modify the value. The default value is “LocalUsersOnly”, you will need to change it to “AllowRemoteUsers”. Save and close the file, then restart the machine.</p> -<p>BEFORE:</p> -<p><a href="https://lh3.googleusercontent.com/-izGUUyhtWyM/X33Bh8YdqGI/AAAAAAAAxuQ/rBbXsqWhe5wZYoGmjXwyyidGmu1kCNVmgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-17.png" alt=""></a></p> -<p>AFTER:</p> -<p><a href="https://lh3.googleusercontent.com/-wFFu1JOXymQ/X33CVp0cImI/AAAAAAAAxug/fibXC6JHmkkilFtWv8641x20flapCibYACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-18.png" alt=""></a></p> - + http://localhost:1313/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ + I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution. Upon installation, AnyConnect pulls down a profile from the ASA containing several settings. This profile is in xml format and is located (on a Windows machine) at %programdata%CiscoCisco AnyConnect Secure Mobility ClientProfileAnyConnectProfile.xsd. To resolve this issue and connect to your VPN, open this file with notepad (or any text editor, run as admin), search for the “WindowsVPNEstablishment” tag, and modify the value. - DHCP Address Negotiation Process - https://rnemeth90.github.io/posts/2014-12-08-dhcp-address-negotiation-process/ + http://localhost:1313/posts/2014-12-08-dhcp-address-negotiation-process/ Mon, 08 Dec 2014 03:08:00 +0000 - - https://rnemeth90.github.io/posts/2014-12-08-dhcp-address-negotiation-process/ - <p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/12/2014-12-07_22h07_33.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/12/2014-12-07_22h07_33.png" alt=""></a></p> - + http://localhost:1313/posts/2014-12-08-dhcp-address-negotiation-process/ + - TCP/IP Network Fundamentals - https://rnemeth90.github.io/posts/2014-11-16-tcpip-network-fundamentals/ + http://localhost:1313/posts/2014-11-16-tcpip-network-fundamentals/ Sun, 16 Nov 2014 21:20:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-16-tcpip-network-fundamentals/ - <p>Going over the basics of network fundamentals and all the models and ideas behind them. The most pushed idea is the OSI networking model which consists of 7 layers, all of which deal with a certain aspect of the networking model.</p> -<p>A P S T N D P</p> -<p>From the top down this represents the following</p> -<p>Layer 7: Application – This layer is the channel between software and external requests. For example, a web server would work with this layer to process HTTP requests.</p> -<p>Layer 6: Presentation – This layer organizes data formats such as JPEG, Text, ASCII, etc</p> -<p>Layer 5: Session – This layer deals with session control; How a conversation should start, function, and end. It can be considered the broken between the layer below and the layers above. It will ensure all the data is proper when being passed up or down.</p> -<p>Layer 4: Transport – This layer is solely focused on data delivery. It deals with many protocols, but most notably it deals with TCP and UDP packets, any checksum errors, and error recovery</p> -<p>Layer 3: Network – This layer deals with logical addressing and routing. It deals with the actual delivery of packets across multiple networks.</p> -<p>Layer 2: Data Link – This layer deals with the rules of how data can be transmitted over a wire such as CSMA/CD and the like. It also deals with encapsulating frames to be transported over a local network</p> -<p>Layer 1: Physical – The actual hardware and electrical signaling to move data over the network. Network cards, cabling, and other hardware are part of this layer</p> -<p>Generic overview of the OSI model above lets work on the idea of some older and modern networks.</p> -<p>Hubs – Devices that simply take a signal and regenerate it out of all ports that are connected.</p> -<p>Switches – Devices that take a signal and make some sort of smart decision to provide a single path from one port to another</p> -<p>Routers – Devices that make decisions based upon higher level information (logical addressing) and will make intelligent decisions on how to handle that data, both incoming and outgoing. Segments networks into two different ones.</p> -<p>Bridge – A device that segments a network in two.</p> -<p>Collision Domain – The bounds where a collision may occur. This is relevant for networks utilizing half-duplex communication and for older devices such as hubs.</p> -<p>Broadcast Domain – The bounds where a broadcast can reach.</p> -<p>Collision Domains: Forgive the visio art, it will get better… hopefully</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h18_36.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h18_36.png" alt=""></a></p> -<p><a href="http://xenodez.pleasedonthack.us/?attachment_id=49">&lt;span style=&ldquo;color: windowtext; font-family: &ldquo;Verdana&rdquo;,sans-serif; font-size: 9.0pt; mso-no-proof: yes; text-decoration: none; text-underline: none;&quot;&gt;</a></p> -<p>Every computer connected to that hub is in the collision domain noted by the circle. With a hub, the signal gets sent to every device connected to it, regardless of whether it was meant to go to that machine or not. When the PC at the top left sends information at the same time as the PC on the bottom right, a collision is likely to occur</p> -<p><a href="http://xenodez.pleasedonthack.us/?attachment_id=52">&lt;span style=&ldquo;color: windowtext; font-family: &ldquo;Verdana&rdquo;,sans-serif; font-size: 9.0pt; mso-no-proof: yes; text-decoration: none; text-underline: none;&quot;&gt;</a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h18_45.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h18_45.png" alt=""></a></p> -<p>Every computer connected to this switch is limited in its collision domain to the port on the switch and the network card in the PC. The reason being that switches do not just take a signal and send it out of all the ports, it is intelligent enough to be able to send information directly to the PC it needs to. This is further mitigated by the fact that a computer connected to a switch may operate at full-duplex, allowing both simultaneous sending and receiving of information.</p> -<p>Collisions and how they are handled:</p> -<p>The way computers avoid collision in this sense is via something called CSMA/CD or Carrier Sense Multiple Access/Collision Avoidance. The way it works is this, a computer will wait until the line is silent before sending information. Every computer will listen to determine whether the line is truly clear. If two computers were to send at the same time, and a collision were to occur, the computers will immediately trigger a random back off time in which they will not try resending that information until the timer is up.</p> -<p>Unicast vs Broadcast vs Multicast</p> -<p>The idea between these concepts is fairly simple. Unicast deals with a transmission that is intended for one recipient. A broadcast is a transmission that is meant for all recipients that are able to hear it. Multicast is intended for a specific group of recipients.</p> - + http://localhost:1313/posts/2014-11-16-tcpip-network-fundamentals/ + Going over the basics of network fundamentals and all the models and ideas behind them. The most pushed idea is the OSI networking model which consists of 7 layers, all of which deal with a certain aspect of the networking model. A P S T N D P From the top down this represents the following Layer 7: Application – This layer is the channel between software and external requests. For example, a web server would work with this layer to process HTTP requests. - Layer 2 Switching Fundamentals - https://rnemeth90.github.io/posts/2012-11-16-layer-2-switching-fundamentals/ + http://localhost:1313/posts/2012-11-16-layer-2-switching-fundamentals/ Fri, 16 Nov 2012 21:26:00 +0000 - - https://rnemeth90.github.io/posts/2012-11-16-layer-2-switching-fundamentals/ - <p>Switches are devices that support a large number of ports to connect devices to the network.</p> -<h3 id="design" >Design: -<span> - <a href="#design"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h3><p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h22_54.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h22_54.png" alt=""></a></p> -<p>More towards a CCNP or CCDA topic, but designing a network when it comes to the switching side can be done in three building blocks. The access layer, the distribution layer, and the core layer. The access layer generally has a high port density, can support VLANs, QoS, and access lists. The distribution layer will aggregate multiple access layer switches. These are also generally Layer 3 switches to allow routing among an enterprise. It will need to be able to handle the volume of traffic in addition to supporting the same features as the access layer switches. The core layer is the device which will need the highest bandwidth backplane to deal with all of the traffic.</p> -<h3 id="how-switches-handle-traffic" >How switches handle traffic: -<span> - <a href="#how-switches-handle-traffic"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h3><p>A switch is an intelligent device that can make some decisions on how to handle the data it is given. Switches can be divided into two categories for these decisions: Layer 2 or Layer 3 switches. For the CCNA we will only be interested in the layer 2 switches. Layer 2 switches operate at the data link layer. This layer deals primarily with MAC addresses. A Layer 2 switch will build a CAM table full of dynamically learned MAC addresses. The way it learns these addresses is by inspecting the layer 2 header/trailer and learning the source MAC addresses on the frames it receives. A frame is what a packet is encapsulated in when it moves from device to device across the network.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h23_04.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_16h23_04.png" alt=""></a></p> -<p>With this example the switch has learned PC1/PC2/and PC3′s MAC addresses. If a packet came in on Fa0/4 from PC4, the switch would look at the source MAC address and put an entry for 4444.4444.4444 on Fa0/4. A switch will route traffic based on this table. There are a few decisions it must make to determine how to handle traffic. When it first receives a frame it will consult it’s CAM table to determine whether or not it has the source MAC address listed for that port. If not, it will add it to the CAM table. In the example above, PC1 sent a frame to the switch, the switch noticed PC1′s MAC address was not in it’s table and added it. The next thing it looks at is the destination MAC address. The CAM table is again consulted. If it finds a match the switch will send the frame directly to the recipient it needs to on whatever port it is on. In the example above, PC1 sends a frame to PC3. Because the switch sees 1111.1111.1111 sending to 3333.3333.3333 and has an entry for 3333.3333.3333 it will send the frame out of port Fa0/3 to the recipient. If a destination is not in the CAM table the switch will need to try to find the recipient. In this case the switch will decide to broadcast the frame out of every port EXCEPT the one it came in on. In this example, PC1 sends a frame destined for PC4. The switch will see a frame from 1111.1111.1111 to 4444.4444.4444. PC4′s MAC address is not in it’s table. The switch will then send the frame out of every port except for Fa0/1 (the source). When PC2 and PC3 get this frame, it will determine if the frame was meant for it, and if not it will ignore it. PC4 will also make the same decision and PC4 will respond. Once PC4 has responded the switch will be able to add PC4′s MAC address to it’s table on Fa0/4.</p> - + http://localhost:1313/posts/2012-11-16-layer-2-switching-fundamentals/ + Switches are devices that support a large number of ports to connect devices to the network. Design: Link to heading More towards a CCNP or CCDA topic, but designing a network when it comes to the switching side can be done in three building blocks. The access layer, the distribution layer, and the core layer. The access layer generally has a high port density, can support VLANs, QoS, and access lists. - diff --git a/public/tags/networking/page/1/index.html b/public/tags/networking/page/1/index.html index 9f7bd10b..360be0bb 100644 --- a/public/tags/networking/page/1/index.html +++ b/public/tags/networking/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/networking/ - + http://localhost:1313/tags/networking/ + - + diff --git a/public/tags/nginx-ingress/index.html b/public/tags/nginx-ingress/index.html new file mode 100644 index 00000000..295ee1a8 --- /dev/null +++ b/public/tags/nginx-ingress/index.html @@ -0,0 +1,234 @@ + + + + + Tag: Nginx-Ingress · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    +
    +

    + Tag: Nginx-Ingress +

    +
    + + + + + + + + + +
    + + +
    + +
    +
    + © + + 2012 - + + 2024 + Ryan Nemeth + · + + Powered by Hugo & Coder. + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/tags/nginx-ingress/index.xml b/public/tags/nginx-ingress/index.xml new file mode 100644 index 00000000..4bf18d0d --- /dev/null +++ b/public/tags/nginx-ingress/index.xml @@ -0,0 +1,19 @@ + + + + Nginx-Ingress on GeekyRyan + http://localhost:1313/tags/nginx-ingress/ + Recent content in Nginx-Ingress on GeekyRyan + Hugo + en + Mon, 11 Dec 2023 00:00:00 +0000 + + + Nginx Ingress Response Header Size - A Cautionary Tale + http://localhost:1313/posts/2023-12-04-nginx-ingress-resp-header-size/ + Mon, 11 Dec 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-12-04-nginx-ingress-resp-header-size/ + This will be a short post about a recent issue I encountered when using Nginx as a Kubernetes ingress. Though, this could also be encountered when using Nginx as a reverse proxy as well. The two definitions are functionally similar. We recently had a client call in complaining of our application returning random 502s (Bad Gateway). After some investigation and the common finger-pointing, I found this entry in the logs of our ingress controllers: + + + diff --git a/public/tags/nginx-ingress/page/1/index.html b/public/tags/nginx-ingress/page/1/index.html new file mode 100644 index 00000000..b24726b7 --- /dev/null +++ b/public/tags/nginx-ingress/page/1/index.html @@ -0,0 +1,10 @@ + + + + http://localhost:1313/tags/nginx-ingress/ + + + + + + diff --git a/public/tags/office365/index.html b/public/tags/office365/index.html index 9f5c3395..a82a7ded 100644 --- a/public/tags/office365/index.html +++ b/public/tags/office365/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Office365 · GeekyRyan + - - -Office365 - GeekyRyan - - - - - - - - - - - + - - + + + - + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,835 +79,201 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - -
    -
    - -

    Tag: Office365

    - - - -
    -
    -
    -

    Azure AD Sync &#8211; Set-MsolDirSyncEnabled : You cannot turn off Active Directory synchronization.

    -
    - -
    - - -
    - I recently ran into a situation in my lab environment that required I resync all (2000+) user accounts to Azure AD. Though this sounds complex and daunting, its actually quite simple. T -The basic steps involve disabling sync, and then removing the user objects. This can all be done with two PowerShell commands: -1) Set-MsolDirSyncEnabled -EnableDirSync $false -2) Get-MsolUser -All | Remove-MsolUser -force -The account that you are currently running the commands as will not be removed. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Azure AD Connect No-Start-Connection

    -
    - -
    - - -
    - This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working. -After forcing the sync, I opened miisclient and noticed some strange errors. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Azure AD Connect Health: Latest Data is not Available in Azure Portal

    -
    - -
    - - -
    - I recently had to create a new Azure AD Connect server, and found that it was not able to report health status in the Azure Portal. After some troubleshooting/research, I was able to get the health status report working by registering the health agent on the server with Azure AD Health Services. Doing this involves running one PowerShell cmdlet on your AD Connect server and providing global administrator credentials. -First, let’s test the status of the agent communication: -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Removing a Forest from Azure AD Connect

    -
    - -
    - - -
    - In an organization with multiple Active Directory forests, you may want to sync objects from trusted forests. Adding trusted forests to Azure AD Sync is a simple process that I will likely cover in a future article. The focus of this post is the not-so-obvious process of removing a forest from Azure AD Connect. This can be a daunting and somewhat scary thing to do. Not fully understanding the process or having someone to guide you can leave you with thoughts like “what happens when I remove the forest from Azure AD Sync? -
    - - -
    - Read more -
    - - - - - - - - -
    - -
    -
    -
    -

    Exchange 2016 Hybrid Deploy Check: Username or Password Invalid

    -
    - -
    - - -
    - These days, it seems every Microsoft product comes with its own unique set of head scratchers. Microsoft Exchange Server is no exception to this. I was installing Exchange 2016 earlier today, to be used as a hybrid configuration server for Office 365 (no local mailboxes). I downloaded the self depackaging executable from Microsoft, and attempted to install it. If you currently have a hybrid configuration (which we did, with Exchange 2010), the Exchange 2016 installer will detect this and run some tests to verify that the Office 365 tenant is ready for Exchange 2016 (more info here: https://technet. -
    - - -
    - Read more -
    - - - - - - - - - -
    - - - -
    -
    -
    -

    How to Permanently Remove Office 365 Users

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Tag: Office365 +

    +
    + +
      -
      - After deleting a user in Office 365, their account is moved to a ‘recycle bin’ for 30 days. This allows the user account to be easily recovered. This can often cause issues when attempting to recreate a mailbox while a hybrid configuration is in place. -To permanently delete the user within Office 365, first delete the user in the Office 365 Admin Portal or using Powershell. Then, connect to your Azure Active Directory environment with Powershell using the “Connect-MsolService” cmdlet. -
      - - -
      - Read more -
      - - - - - - - - - -
    +
  • + 2020-11-26 + Azure AD Sync &#8211; Set-MsolDirSyncEnabled : You cannot turn off Active Directory synchronization. +
  • -
    -
    -
    -

    Script for Setting the License for Multiple Office 365 User Accounts

    -
    - -
    - +
  • + 2018-07-26 + Azure AD Connect No-Start-Connection +
  • -
    - A script for setting the Office 365 license for multiple users. Requires a CSV file named users.csv. This file must in the same directory as the script. The CSV file must contain three columns. The title of the columns should be UPN, UsageLocation, and SKU. -BulkSet-MsolUserLicense.ps1 -
    +
  • + 2018-07-18 + Azure AD Connect Health: Latest Data is not Available in Azure Portal +
  • +
  • + 2018-07-13 + Removing a Forest from Azure AD Connect +
  • +
  • + 2017-11-07 + Exchange 2016 Hybrid Deploy Check: Username or Password Invalid +
  • +
  • + 2017-06-26 + New Script: BulkAdd-SpamFilterWhitelist.ps1 +
  • - +
  • + 2017-06-20 + How to Permanently Remove Office 365 Users +
  • - - - - -
    +
  • + 2015-08-13 + Error When Reinstalling DirSync +
  • -
    -
    -
    -

    Azure AD Connect Password Sync &#8211; Disabled and Grayed Out

    -
    - -
    + + - -
    - Ran into a problem earlier with the new Azure AD Connect Wizard. We had configured the wizard and synced around 500 AD accounts. However, password sync was not working. I opened the wizard to confirm the configuration and found that “Password Hash Synchronization” was disabled. It was greyed out and could not be enabled. -I called Microsoft and worked for a couple hours with a technician to resolve the issue. Thought I should post the resolution here in case anyone else encounters this. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Error When Reinstalling DirSync

    -
    -
    +
    +
    + © -
    - Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process: -I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do: -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2015-08-13-error-when-reinstalling-dirsync/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/office365/index.xml b/public/tags/office365/index.xml index ce014489..cd32b68b 100644 --- a/public/tags/office365/index.xml +++ b/public/tags/office365/index.xml @@ -2,233 +2,81 @@ Office365 on GeekyRyan - https://rnemeth90.github.io/tags/office365/ - GeekyRyan (Office365) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/office365/ + Recent content in Office365 on GeekyRyan + Hugo + en Thu, 26 Nov 2020 16:31:00 +0000 - - - - + Azure AD Sync &#8211; Set-MsolDirSyncEnabled : You cannot turn off Active Directory synchronization. - https://rnemeth90.github.io/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ + http://localhost:1313/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ Thu, 26 Nov 2020 16:31:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ - <p>I recently ran into a situation in my lab environment that required I resync all (2000+) user accounts to Azure AD. Though this sounds complex and daunting, its actually quite simple. T</p> -<p>The basic steps involve disabling sync, and then removing the user objects. This can all be done with two PowerShell commands:</p> -<p>1) Set-MsolDirSyncEnabled -EnableDirSync $false</p> -<p><a href="https://lh3.googleusercontent.com/-rGK18FXw7ns/X7_WthQR0CI/AAAAAAAAyCM/gg7MsY2fcVIcWMMbvxYzPpbpPyKwgHP8ACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image.png" alt=""></a></p> -<p>2) Get-MsolUser -All | Remove-MsolUser -force</p> -<p><a href="https://lh3.googleusercontent.com/-miyfN7OISGo/X7_WzDCc6iI/AAAAAAAAyCQ/PtHURTTVMQ4uypzO7L1UaLfyEs0fpYGdACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-1.png" alt=""></a></p> -<p>The account that you are currently running the commands as will not be removed.</p> -<p>To enable Azure AD Sync, you simply reverse the boolean operation on the Set-MsolDirSyncEnabled cmdlet above. However, I ran into an issue when trying to enable Azure AD Sync.</p> -<p><a href="https://lh3.googleusercontent.com/-R1TPVgYaEBE/X7_XM5_ljKI/AAAAAAAAyCY/VIJZnlgNEPQbhL9p3D0J3XsekBrGiNS3QCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-2.png" alt=""></a></p> -<p>After some research, it turns out you must wait a period of time (up to 12 hours in some cases) before you can make a second change to the Azure AD Sync status. This error simply means that we made a recent change to Azure AD Sync, and we must wait before making another change. To prove this, there is a “DirectorySynchronizationStatus” member for the Get-MsolCompanyInformation cmdlet. If we take a look at this member, we can see the status is “PendingDisabled”.</p> -<p><a href="https://lh3.googleusercontent.com/-0OBwKDDD5xQ/X7_X1bBxXjI/AAAAAAAAyCk/FyRlaMpCDT4aBe08TL_8sLiwUBnHkcPJQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-3.png" alt=""></a></p> -<p>Check the status of this periodically over the next 12 hours or so, and once it says “Enabled” or “Disabled”, you should be able to change the state once more.</p> - + http://localhost:1313/posts/2020-11-26-azure-ad-sync-set-msoldirsyncenabled/ + I recently ran into a situation in my lab environment that required I resync all (2000+) user accounts to Azure AD. Though this sounds complex and daunting, its actually quite simple. T The basic steps involve disabling sync, and then removing the user objects. This can all be done with two PowerShell commands: 1) Set-MsolDirSyncEnabled -EnableDirSync $false 2) Get-MsolUser -All | Remove-MsolUser -force The account that you are currently running the commands as will not be removed. - Azure AD Connect No-Start-Connection - https://rnemeth90.github.io/posts/2018-07-26-azure-ad-connect-no-start-connection/ + http://localhost:1313/posts/2018-07-26-azure-ad-connect-no-start-connection/ Thu, 26 Jul 2018 12:22:00 +0000 - - https://rnemeth90.github.io/posts/2018-07-26-azure-ad-connect-no-start-connection/ - <p>This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working.</p> -<p>After forcing the sync, I opened miisclient and noticed some strange errors. We sync multiple on-prem AD forests to Azure AD, and the status for one of them was “no-start-connection”. That error in itself does not seem significant to me. However, after clicking on the “failed-connection” link in the Connection Status pane, things became much more clear.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_05.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_05.png" alt=""></a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_18.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-26_08h03_18.png" alt=""></a></p> -<p>The domain controllers for the forest in question are in a datacenter that is geographically separated from the datacenter that our Azure AD Sync server lives in. The two sites are connected via a S2S VPN.</p> -<p>There was obviously some type of connection issue between our two datacenters. In my case, the issue was transient, and resolved itself after a few minutes. But if you’re experiencing this error message, check your L2/L3 connection. Also, verify DNS is working and someone didn’t make changes to your firewall(s). Just walk up or down the OSI model and you’ll eventually find the problem.</p> - + http://localhost:1313/posts/2018-07-26-azure-ad-connect-no-start-connection/ + This morning, I ran into an issue with Azure AD Connect that I had never seen before. I received an email alert from Azure AD stating that Password Synchronization was not working for my forest, and the suggested fix was to restart the ADSync service on the server. I restarted the service and then forced a sync to verify it was working. After forcing the sync, I opened miisclient and noticed some strange errors. - Azure AD Connect Health: Latest Data is not Available in Azure Portal - https://rnemeth90.github.io/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ + http://localhost:1313/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ Wed, 18 Jul 2018 16:38:00 +0000 - - https://rnemeth90.github.io/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ - <p>I recently had to create a new Azure AD Connect server, and found that it was not able to report health status in the Azure Portal. After some troubleshooting/research, I was able to get the health status report working by registering the health agent on the server with Azure AD Health Services. Doing this involves running one PowerShell cmdlet on your AD Connect server and providing global administrator credentials.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_56.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_56.png" alt=""></a></p> -<p>First, let’s test the status of the agent communication:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_19.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_19.png" alt=""></a></p> -<p>If you do not receive any errors, that means the Azure AD Connect Health agent on your server is able to successfully communicate with the cloud service. Now, let’s register the agent:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_05.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_05.png" alt=""></a></p> -<p>You will be prompted for credentials. The credentials you provide need to be a global administrator account in your Azure AD tenant.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_42.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h23_42.png" alt=""></a></p> -<p>You should receive some output stating that the registration is successful (or it failed).</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h25_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h25_20.png" alt=""></a></p> -<p>Now, just go back to the Azure Portal and refresh the page. The message stating that the -“latest data is not available” should be gone.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h36_42.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-18_12h36_42.png" alt=""></a></p> - + http://localhost:1313/posts/2018-07-18-azure-ad-connect-health-latest-data-is/ + I recently had to create a new Azure AD Connect server, and found that it was not able to report health status in the Azure Portal. After some troubleshooting/research, I was able to get the health status report working by registering the health agent on the server with Azure AD Health Services. Doing this involves running one PowerShell cmdlet on your AD Connect server and providing global administrator credentials. First, let’s test the status of the agent communication: - Removing a Forest from Azure AD Connect - https://rnemeth90.github.io/posts/2018-07-13-removing-forest-from-azure-ad-connect/ + http://localhost:1313/posts/2018-07-13-removing-forest-from-azure-ad-connect/ Fri, 13 Jul 2018 15:30:00 +0000 - - https://rnemeth90.github.io/posts/2018-07-13-removing-forest-from-azure-ad-connect/ - <p>In an organization with multiple Active Directory forests, you may want to sync objects from trusted forests. Adding trusted forests to Azure AD Sync is a simple process that I will likely cover in a future article. The focus of this post is the not-so-obvious process of removing a forest from Azure AD Connect. This can be a daunting and somewhat scary thing to do. Not fully understanding the process or having someone to guide you can leave you with thoughts like “what happens when I remove the forest from Azure AD Sync? Do on-premises objects get deleted? Are cloud objects deleted?”. I will try to answer these questions to the best of my ability and hopefully make the process simple and stress-free for you.</p> -<p>To get started, we first need to open PowerShell and disable the AD Sync scheduler. You can do this by running the “Set-ADSyncScheduler” cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h47_05.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h47_05.png" alt=""></a></p> -<p>This cmdlet is included in the ADSync PowerShell module. You may need to load the module prior to using the cmdlet:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Import-Module ADSync -</span></span></code></pre></div><p>The next step is to open FIM (miisclient) located in the install directory of Microsoft Azure AD Sync. By default, this is C:Program FilesMicrosoft Azure AD SyncUIShellmiisclient.exe. Once you have FIM open, click on the Connectors tab, then right click on the connector for the forest that you want to delete, and click “Delete”.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_26.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_26.png" alt=""></a></p> -<p>You will then be prompted, asking if you want to just delete the Connector Space, or delete the Connector and the Connector Space. The former open removes all data, but keeps the configuration in case you want to use it again later. The latter option deleted the data and the configuration. This open should only be used if you don’t plan on syncing the forest again.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_09.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h50_09.png" alt=""></a></p> -<p>The connector for the forest is now deleted, but what actually happens? Your on-premises objects do not get removed for the forest, and cloud objects <strong>are</strong> removed. Simple enough, right?</p> -<p>Now you just need to re-enable the AD Sync Scheduler with this cmdlet:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Set-ADSyncScheduler -SyncCycleEnabled $true -</span></span></code></pre></div><p>One last thing to mention… You may receive an email from the Microsoft Online Services Team stating that the identity synchronization failed due to a deletion threshold being met. By default, Azure AD Connect will not allow you to delete more than 500 objects in your cloud directory. This is to protect you from making a careless (potentially resume generating) mistake. The email will look something like this:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h56_04.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_10h56_04.png" alt=""></a></p> -<p>If you are certain that you want to proceed with deleting the objects, here are the steps:</p> -<ol> -<li> -<p>Disable the deletion threshold protection. Open PowerShell on your Azure AD Sync server and type in this cmdlet: Disable-ADSyncExportDeletionThreshold. You will be prompted for credentials, sign-in with an Azure AD Global Admin account.</p> -</li> -<li> -<p>Open FIM (miisclient), and click on the “Connectors” button at the top of the window. Right click on the connector of type “Windows Azure Active Directory”, and select “Run…”.</p> -</li> -</ol> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_39.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_39.png" alt=""></a></p> -<ol start="3"> -<li>Next, click Export and then click Ok.</li> -</ol> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_58.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/07/2018-07-13_11h07_58.png" alt=""></a></p> -<ol start="4"> -<li> -<p>Allow the connector to run. This will take a few minutes. You can monitor the progress by clicking the Operations button.</p> -</li> -<li> -<p>Once this completes, you need to re-enable the deletion threshold. You can do this by running this cmdlet: <span style="background: #F9F9F9;"></p> -</li> -</ol> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Enable-ADSyncExportDeletionThreshold -DeletionThreshold <span style="color:#ae81ff">500</span>. -</span></span></code></pre></div><p>You will be prompted for credentials again. Just type in your Azure AD Global Admin creds. You can even lower the threshold if you’d like. I set mine to 100.</p> - + http://localhost:1313/posts/2018-07-13-removing-forest-from-azure-ad-connect/ + In an organization with multiple Active Directory forests, you may want to sync objects from trusted forests. Adding trusted forests to Azure AD Sync is a simple process that I will likely cover in a future article. The focus of this post is the not-so-obvious process of removing a forest from Azure AD Connect. This can be a daunting and somewhat scary thing to do. Not fully understanding the process or having someone to guide you can leave you with thoughts like “what happens when I remove the forest from Azure AD Sync? - Exchange 2016 Hybrid Deploy Check: Username or Password Invalid - https://rnemeth90.github.io/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ + http://localhost:1313/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ Tue, 07 Nov 2017 13:30:00 +0000 - - https://rnemeth90.github.io/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ - <p>These days, it seems every Microsoft product comes with its own unique set of head scratchers. Microsoft Exchange Server is no exception to this. I was installing Exchange 2016 earlier today, to be used as a hybrid configuration server for Office 365 (no local mailboxes). I downloaded the self depackaging executable from Microsoft, and attempted to install it. If you currently have a hybrid configuration (which we did, with Exchange 2010), the Exchange 2016 installer will detect this and run some tests to verify that the Office 365 tenant is ready for Exchange 2016 (more info here: <a href="https://technet.microsoft.com/en-us/library/ms.exch.setup.hybridconfigurationstatuspage(v=exchg.160).aspx">https://technet.microsoft.com/en-us/library/ms.exch.setup.hybridconfigurationstatuspage(v=exchg.160).aspx</a>). You’ll be prompted for Office 365 credentials (the user must have the Organization Management role). Seems simple enough, right? Wrong.</p> -<p>After typing in the username and <em>pasting</em> the password into the password field, setup came back with an error message stating the username or password was wrong. I then clicked the back button, and it crashed. I ran through this process a few more times, all with the same outcome. I even rebooted the server, which (in my opinion) should never be the resolution to a software problem. I looked through setup logs and found no indication of what the problem could be…</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2017/11/2017-11-07_12h57_08.png" alt=""></p> -<p>It was on the fourth try that I typed in the password, and this seemed to work. I didn’t receive any error messages about the credentials being wrong. The Exchange setup seemed to continue on successfully. However, it then failed with a different error:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2017/11/2017-11-07_13h12_02.png" alt=""></p> -<p>I again looked through the setup logs and found that this error happened anytime setup tried to run the “Get-OrganizationConfig” cmdlet. After troubleshooting for a little while, and no resolution in sight, I turned to Google. One of the posts I came across said that this is a bug in the Exchange installer, and to try and use the Cumulative Update installer instead. Apparently, with Exchange 2016, the Cumulative Update installer’s include all of the Exchange binaries, not just the updated binaries. I downloaded the installer for CU7 (all 6 gigabytes of it…) and successfully installed Exchange 2016. Hope this helps anyone out there struggling with this.</p> - + http://localhost:1313/posts/2017-11-07-exchange-2016-hybrid-deploy-check-username-or-password-invalid/ + These days, it seems every Microsoft product comes with its own unique set of head scratchers. Microsoft Exchange Server is no exception to this. I was installing Exchange 2016 earlier today, to be used as a hybrid configuration server for Office 365 (no local mailboxes). I downloaded the self depackaging executable from Microsoft, and attempted to install it. If you currently have a hybrid configuration (which we did, with Exchange 2010), the Exchange 2016 installer will detect this and run some tests to verify that the Office 365 tenant is ready for Exchange 2016 (more info here: https://technet. - New Script: BulkAdd-SpamFilterWhitelist.ps1 - https://rnemeth90.github.io/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ + http://localhost:1313/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ Mon, 26 Jun 2017 22:16:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ - <p>This script is capable of adding a list of domains to an Exchange Online Spam Filter policy. It can be downloaded from TechNet or Github.</p> -<p><a href="https://github.com/rnemeth90/PowerShell/blob/master/BulkAdd-SpamFilterWhitelist.ps1">Github</a></p> -<p><a href="https://gallery.technet.microsoft.com/BulkAdd-SpamFilterWhitelist-2d2b596a">TechNet</a></p> - + http://localhost:1313/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ + This script is capable of adding a list of domains to an Exchange Online Spam Filter policy. It can be downloaded from TechNet or Github. Github TechNet - How to Permanently Remove Office 365 Users - https://rnemeth90.github.io/posts/2017-06-20-how-to-permanently-remove-office-365-users/ + http://localhost:1313/posts/2017-06-20-how-to-permanently-remove-office-365-users/ Tue, 20 Jun 2017 18:13:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-20-how-to-permanently-remove-office-365-users/ - <p>After deleting a user in Office 365, their account is moved to a ‘recycle bin’ for 30 days. This allows the user account to be easily recovered. This can often cause issues when attempting to recreate a mailbox while a hybrid configuration is in place.</p> -<p>To permanently delete the user within Office 365, first delete the user in the Office 365 Admin Portal or using Powershell. Then, connect to your Azure Active Directory environment with Powershell using the “Connect-MsolService” cmdlet.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h06_20.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h06_20.png" alt=""></a></p> -<p>To see a list of user accounts currently in the recycle bin, run this cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h09_47.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h09_47.png" alt=""></a></p> -<p>Then, to permanently delete all accounts in the recycle bin, run this cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h10_16.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h10_16.png" alt=""></a></p> -<p>To remove a specific user, run this cmdlet:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h11_15.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2017-06-20_14h11_15.png" alt=""></a></p> - + http://localhost:1313/posts/2017-06-20-how-to-permanently-remove-office-365-users/ + After deleting a user in Office 365, their account is moved to a ‘recycle bin’ for 30 days. This allows the user account to be easily recovered. This can often cause issues when attempting to recreate a mailbox while a hybrid configuration is in place. To permanently delete the user within Office 365, first delete the user in the Office 365 Admin Portal or using Powershell. Then, connect to your Azure Active Directory environment with Powershell using the “Connect-MsolService” cmdlet. - Script for Setting the License for Multiple Office 365 User Accounts - https://rnemeth90.github.io/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ + http://localhost:1313/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ Mon, 11 Apr 2016 01:25:00 +0000 - - https://rnemeth90.github.io/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ - <p>A script for setting the Office 365 license for multiple users. Requires a CSV file named users.csv. This file must in the same directory as the script. The CSV file must contain three columns. The title of the columns should be UPN, UsageLocation, and SKU.</p> -<p><a href="https://drive.google.com/open?id=0B2K6VOnt6zeXZ2Z6OFZhZVoyenc">BulkSet-MsolUserLicense.ps1</a></p> - + http://localhost:1313/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ + A script for setting the Office 365 license for multiple users. Requires a CSV file named users.csv. This file must in the same directory as the script. The CSV file must contain three columns. The title of the columns should be UPN, UsageLocation, and SKU. BulkSet-MsolUserLicense.ps1 - Azure AD Connect Password Sync &#8211; Disabled and Grayed Out - https://rnemeth90.github.io/posts/2015-10-15-azure-ad-connect-password-sync-disabled/ + http://localhost:1313/posts/2015-10-15-azure-ad-connect-password-sync-disabled/ Thu, 15 Oct 2015 10:18:00 +0000 - - https://rnemeth90.github.io/posts/2015-10-15-azure-ad-connect-password-sync-disabled/ - <p>Ran into a problem earlier with the new Azure AD Connect Wizard. We had configured the wizard and synced around 500 AD accounts. However, password sync was not working. I opened the wizard to confirm the configuration and found that “Password Hash Synchronization” was disabled. It was greyed out and could not be enabled.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_08h43_18.jpg"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_08h43_18.jpg" alt=""></a></p> -<p>I called Microsoft and worked for a couple hours with a technician to resolve the issue. Thought I should post the resolution here in case anyone else encounters this.</p> -<p>You can enable password sync by running the following script:</p> -<p>Import-Module ADSync</p> -<p>$adConnector = “&lt;Local AD Connector Name&gt;”</p> -<p>$aadConnector = “&lt;Azure AD Connector Name&gt;”</p> -<p>Set-ADSyncAADPasswordSyncState -ConnectorName $aadConnector –Enable $true</p> -<p>Set-ADSyncAADPasswordSyncConfiguration -SourceConnector $adConnector -TargetConnector $aadConnector -Enable $true</p> -<p>get-ADSyncAADPasswordSyncConfiguration -sourceconnector $adConnector</p> -<p>You need to set the value of the $adConnector and $aadConnector variables with the names of your Connectors found in the MIISClient.</p> -<p>Open the MIISClient by browsing to:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_09h39_42.jpg"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_09h39_42.jpg" alt=""></a></p> -<p>Right click on MIISClient.exe and click “Run As Administrator”.</p> -<p>You can obtain the names of your connectors in by going to the Connectors tab and looking at the Names column. There are two values here that you need to pay attention to. The Windows Azure Active Directory connector is your Azure Connector (obviously), and the other connector is your on-prem connector.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_09h39_31.jpg"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_09h39_31.jpg" alt=""></a></p> -<p>Now that you have the names, just plug them into the script and run it. You can go back to the Azure AD Connect Wizard and verify that password sync is enabled. You can also go to the Event Viewer -&gt; Application log and look for events 576 and 577. These two events are related to password sync and should show you all AD accounts that have successfully synced passwords.</p> -<p>You can force a sync by going to this location and running “DirectorySyncClientCmd.exe”.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_10h21_12.jpg"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/10/2015-10-15_10h21_12.jpg" alt=""></a></p> - + http://localhost:1313/posts/2015-10-15-azure-ad-connect-password-sync-disabled/ + Ran into a problem earlier with the new Azure AD Connect Wizard. We had configured the wizard and synced around 500 AD accounts. However, password sync was not working. I opened the wizard to confirm the configuration and found that “Password Hash Synchronization” was disabled. It was greyed out and could not be enabled. I called Microsoft and worked for a couple hours with a technician to resolve the issue. Thought I should post the resolution here in case anyone else encounters this. - Error When Reinstalling DirSync - https://rnemeth90.github.io/posts/2015-08-13-error-when-reinstalling-dirsync/ + http://localhost:1313/posts/2015-08-13-error-when-reinstalling-dirsync/ Thu, 13 Aug 2015 18:59:00 +0000 - - https://rnemeth90.github.io/posts/2015-08-13-error-when-reinstalling-dirsync/ - <p>Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process:</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2015/08/1.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/1.png" alt=""></a></p> -<p>I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do:</p> -<ul> -<li>Uninstall Windows Azure Active Directory Sync tool and reboot -<a href="https://geekyryan.com/wp-content/uploads/2015/08/2.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/2.png" alt=""></a></li> -</ul> -<p>Remove this directory and all subfolders: C:Program FilesWindows Azure Active Directory Sync -<a href="https://geekyryan.com/wp-content/uploads/2015/08/3.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/3.png" alt=""></a></p> -<p>If you created a domain account to use for DirSync, remove it. Also remove the Office 365 account you created.</p> -<ul> -<li>Delete the Group accounts that the DirSync wizard created. Their names all begin with “FIM”</li> -</ul> -<p><a href="https://geekyryan.com/wp-content/uploads/2015/08/4.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/4.png" alt=""></a></p> -<p>Uninstall MSSQL:</p> -<ul> -<li>Delete the MSSQL directory: C:Program FilesMicrosoft SQL Server</li> -<li>Reboot!</li> -<li>You should be able to install and configure DirSync now.</li> -</ul> -<p><a href="https://geekyryan.com/wp-content/uploads/2015/08/5.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/5.png" alt=""></a></p> - + http://localhost:1313/posts/2015-08-13-error-when-reinstalling-dirsync/ + Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process: I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do: - diff --git a/public/tags/office365/page/1/index.html b/public/tags/office365/page/1/index.html index a806a7cd..9b24646e 100644 --- a/public/tags/office365/page/1/index.html +++ b/public/tags/office365/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/office365/ - + http://localhost:1313/tags/office365/ + - + diff --git a/public/tags/pod-eviction/index.html b/public/tags/pod-eviction/index.html index aba615d1..d31a3e21 100644 --- a/public/tags/pod-eviction/index.html +++ b/public/tags/pod-eviction/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Pod Eviction · GeekyRyan + - - -pod eviction - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,301 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Tag: pod eviction

    - - - -
    -
    -
    -

    Kubernetes Pod Eviction

    -
    -
    +
    +
    + © -
    - In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation. -What is Pod Eviction? Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/pod-eviction/index.xml b/public/tags/pod-eviction/index.xml index 3642b240..39cda360 100644 --- a/public/tags/pod-eviction/index.xml +++ b/public/tags/pod-eviction/index.xml @@ -1,85 +1,19 @@ - pod eviction on GeekyRyan - https://rnemeth90.github.io/tags/pod-eviction/ - GeekyRyan (pod eviction) - Hugo -- gohugo.io - en-us + Pod Eviction on GeekyRyan + http://localhost:1313/tags/pod-eviction/ + Recent content in Pod Eviction on GeekyRyan + Hugo + en Sat, 05 Feb 2022 23:49:16 +0000 - - - - + Kubernetes Pod Eviction - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ Sat, 05 Feb 2022 23:49:16 +0000 - - https://rnemeth90.github.io/posts/2022-02-05-kubernetes-pod-eviction/ - <p>In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation.</p> -<h2 id="what-is-pod-eviction" >What is Pod Eviction? -<span> - <a href="#what-is-pod-eviction"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. The most common of which is resource starvation on a node. This is referred to as “node-pressure eviction.”</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>NAME READY STATUS RESTARTS AGE -</span></span><span style="display:flex;"><span>nginx 0/1 Evicted <span style="color:#ae81ff">0</span> 10s -</span></span></code></pre></div><h2 id="eviction-process" >Eviction Process -<span> - <a href="#eviction-process"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The kubelet process running on the node monitors resources such as CPU, memory, disk space, inodes, etc. When one of these resources reaches a certain consumption level, the kubelet will first attempt to clean up resources by deleting non-running pods and images (in the case of storage starvation). The kubelet will then fail one or more pods on the node to reclaim resources. The class of the pod determines the order in which it does this.</p> -<p><strong>Pod Classes</strong></p> -<ul> -<li>Guaranteed: Pods that have requests and limits configured for both CPU and memory</li> -<li>Burstable: Pods with a resource request configured for memory or CPU</li> -<li>Best Effort: Pods without any requests or limits</li> -</ul> -<p>The kubelet will first evict any “best-effort” pods. If this is not enough, the kubelet will evict any “burstable” pods. Pods within the “guaranteed” class are theoretically safe from eviction.</p> -<p>During a node-pressure eviction, the kubelet sets the PodPhase for the selected pods to “Failed.” This causes the pods to terminate. If a daemonSet or replicaSet manages the pod, the Kubernetes controller-manager will create new pods on another node.</p> -<h2 id="recovery" >Recovery -<span> - <a href="#recovery"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Node-pressure eviction is almost always avoidable. We can prevent this type of issue by ensuring that we properly size our clusters and create resource limits for pods.</p> -<p><strong>Resource</strong> <strong>Requests and Limits:</strong></p> -<ul> -<li>Requests: The minimum amount of resources (CPU/memory) that a container needs to start.</li> -<li>Limits: The maximum amount of resources that a container is allowed to use.</li> -</ul> -<p>Pod resources and requests can be defined in a pod spec or deployment spec. Below is an example of a pod spec with resource requests and limits defined:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">frontend</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">nginx</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;64Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;250m&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">limits</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">memory</span>: <span style="color:#e6db74">&#34;128Mi&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">cpu</span>: <span style="color:#e6db74">&#34;500m&#34;</span> -</span></span></code></pre></div><p>You will often need to clean up evicted pods manually. If you find that your cluster has a large amount of evicted pods, you can clean them up with the following kubectl commands:</p> -<p><strong>To see all failed pods in the cluster:</strong></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl get pod --all-namespaces --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Failed -</span></span></code></pre></div><p><strong>To remove all failed pods in the cluster:</strong></p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>kubectl delete pod --all-namespaces --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Failed -</span></span></code></pre></div><p>I hope this article has been helpful. Please reach out if you have any questions or comments! Also, if you would like to learn more, take a look at the official Kubernetes docs:</p> -<p><a href="https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/">https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/</a></p> - + http://localhost:1313/posts/2022-02-05-kubernetes-pod-eviction/ + In this article, we will dive into the process of pod eviction in a Kubernetes cluster, how you can pod prevent pod eviction, and how you can recover from such a situation. What is Pod Eviction? Link to heading Kubernetes pod eviction is a type of involuntary service disruption in which a pod is forcefully stopped on a node or fails to be scheduled on a node. Pod eviction can happen for a variety of reasons. - diff --git a/public/tags/pod-eviction/page/1/index.html b/public/tags/pod-eviction/page/1/index.html index 418b7a29..21d9834b 100644 --- a/public/tags/pod-eviction/page/1/index.html +++ b/public/tags/pod-eviction/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/pod-eviction/ - + http://localhost:1313/tags/pod-eviction/ + - + diff --git a/public/tags/powershell/index.html b/public/tags/powershell/index.html index 9493d975..ca03a7fe 100644 --- a/public/tags/powershell/index.html +++ b/public/tags/powershell/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: PowerShell · GeekyRyan + - - -Powershell - GeekyRyan - - - + - - - + + + - - + + + + + + + + + - + + + + - - - - - - - - - - - - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,442 +79,166 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - + + + - - - - - - - - -
    -
    - -

    Tag: Powershell

    - - - -
    -
    -
    -

    Using try/catch/finally Blocks in PowerShell

    -
    - -
    - - -
    - Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it’s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we’ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn’t crash when the unexpected occurs. -
    - - -
    - Read more -
    - - - +
    + + + +
    +
  • + 2022-06-04 + Remove Kubernetes Namespace Stuck in the Terminating State +
  • -
    -
    -
    -

    Powershell for Devops - Querying REST APIs with Powershell

    -
    - -
    + + - -
    - This will be a short post on querying REST APIs with Powershell. -It’s hard to argue that REST APIs are the predominant technology for interacting with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) product without having to go through the exercise of a more complicated integration. REST APIs communicate in a common format, typically JSON. However, most will allow us to choose the response format by specifying an option in the ‘Accept’ header. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Remove Kubernetes Namespace Stuck in the Terminating State

    -
    -
    +
    +
    + © -
    - In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state. -A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - +
    +
    +
    - + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/tags/powershell/index.xml b/public/tags/powershell/index.xml index b84478e6..baf8f94f 100644 --- a/public/tags/powershell/index.xml +++ b/public/tags/powershell/index.xml @@ -1,264 +1,33 @@ - Powershell on GeekyRyan - https://rnemeth90.github.io/tags/powershell/ - GeekyRyan (Powershell) - Hugo -- gohugo.io - en-us + PowerShell on GeekyRyan + http://localhost:1313/tags/powershell/ + Recent content in PowerShell on GeekyRyan + Hugo + en Tue, 15 Aug 2023 00:00:00 +0000 - - - - + Using try/catch/finally Blocks in PowerShell - https://rnemeth90.github.io/posts/2023-08-15-powershell-try-catch/ + http://localhost:1313/posts/2023-08-15-powershell-try-catch/ Tue, 15 Aug 2023 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2023-08-15-powershell-try-catch/ - <p>Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it&rsquo;s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we&rsquo;ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn&rsquo;t crash when the unexpected occurs. We&rsquo;ll then cover the differences in terminating and non-terminating errors and why you should take these into consideration when implementing error handling.</p> -<h2 id="the-try-block" >The Try Block -<span> - <a href="#the-try-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The Try block is where you place the code that might generate an error. Think of it as a protective bubble around your potentially troublesome code. If an error occurs within the Try block, PowerShell will immediately jump to the corresponding Catch block.</p> -<p>Here&rsquo;s a simple example:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><h2 id="the-catch-block" >The Catch Block -<span> - <a href="#the-catch-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The Catch block is where you can handle the error. PowerShell provides you with a special variable $_ that contains information about the error. You can use this variable to display error messages or even take corrective actions.</p> -<p>In the example above, we&rsquo;re capturing the error generated by attempting to retrieve a nonexistent file. The $_ variable holds the error message, which we&rsquo;re displaying using Write-Host.</p> -<h2 id="the-finally-block" >The Finally Block -<span> - <a href="#the-finally-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Now, let&rsquo;s talk about the unsung hero – the Finally block. This block is executed regardless of whether an error occurred or not. It&rsquo;s where you can place cleanup code that ensures your script leaves no trace behind, even in the face of adversity. Some tasks that are commonly done in the finally block are closing database connections, removing temp files, etc. The finally block is completely optional.</p> -<pre tabindex="0"><code> -try { - # Code that might generate an error - # ... -} -catch { - # Code to handle the error - # ... -} -finally { - # Cleanup code here - # ... -} -</code></pre><h2 id="terminatingnon-terminating-errors" >Terminating/non-terminating Errors -<span> - <a href="#terminatingnon-terminating-errors"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>non-terminating errors are any error that will not stop the execution of your script. Most cmdlets in PowerShell are non-terminating. They may output an error, but your script will continue to run. These kinds of errors cannot be caught with a catch block by default. The reason for this is the default <code>ErrorAction</code> in your PowerShell profile, which is set to <code>Continue</code>.</p> -<pre tabindex="0"><code># To show your default error action type -$ErrorActionPreference -</code></pre><p>Let&rsquo;s go back and look at our first example:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><p>If you took the time to run this code, you may have noticed that the <code>Write-Host</code> cmdlet in the <code>catch</code> block was never ran. Why did we get a red error message in our PowerShell console, rather than the text <code>An error occurred: ...</code>? The reason is that the non-existing path isn&rsquo;t a terminating error, and the default <code>ErrorAction</code> is <code>Continue</code>. To catch the error, you will need to change the <code>ErrorAction</code> in your PowerShell console to <code>Stop</code>. This can be done in multiple ways. You can add <code>-ErrorAction Stop</code> to the cmdlet, like this:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -ErrorAction Stop -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><p>Or you can change the <code>ErrorActionPreference</code> for the entire script, by adding this to the top of the script:</p> -<pre tabindex="0"><code>$ErrorActionPreference = &#34;Stop&#34; -</code></pre><h2 id="exceptions" >Exceptions -<span> - <a href="#exceptions"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>If you have ever worked with exceptions in C# you can skip this section. In the previous examples, we used simple <code>catch</code> blocks that will catch <em>any</em> error. This is a good start, but we can do better. PowerShell allows you to catch individual exceptions based on the exception type, similar to how C# handles catching exceptions.</p> -<p>Let&rsquo;s look at an example:</p> -<pre tabindex="0"><code>try { - # Attempt to open a non-existent file - $file = Get-Content -Path &#34;NonexistentFile.txt&#34; -} -catch [System.IO.FileNotFoundException] { - Write-Host &#34;Caught a FileNotFoundException: $_&#34; -} -catch { - Write-Host &#34;Caught an exception: $_&#34; -} -</code></pre><p>We now have two <code>catch</code> blocks. If we encounter an exception of type <code>System.IO.FileNotFoundException</code>, the first <code>catch</code> block will catch the exception and handle it accordingly. The second <code>catch</code> block will handle any other generic error.</p> -<h2 id="conclusion" >Conclusion -<span> - <a href="#conclusion"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Error handling might seem daunting at first, but with the power of Try-Catch-Finally blocks at your fingertips, you&rsquo;re well-equipped to handle errors gracefully and ensure the resilience of your PowerShell scripts. Remember, every error is an opportunity to refine your skills and make your scripts more robust.</p> -<p>Thanks for reading!</p> -<p>Official Microsoft Documentation for Try-Catch-Finally in PowerShell: -<a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-7.3">about_try_catch_finally</a></p> - + http://localhost:1313/posts/2023-08-15-powershell-try-catch/ + Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it&rsquo;s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we&rsquo;ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn&rsquo;t crash when the unexpected occurs. - Powershell for Devops - Querying REST APIs with Powershell - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ Thu, 04 Aug 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ - <p>This will be a short post on querying REST APIs with Powershell.</p> -<p>It&rsquo;s hard to argue that REST APIs are the predominant technology for interacting -with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) -product without having to go through the exercise of a more complicated integration. REST APIs communicate -in a common format, typically JSON. However, most will allow us to choose the response format by specifying an -option in the &lsquo;Accept&rsquo; header. Most languages provide a native method for interacting with -REST APIs. This objective for this post is to show you how simple this is with Powershell.</p> -<p>To get started, we&rsquo;ll need a public API to interact with. I&rsquo;m going to use <a href="https://icanhazdadjoke.com/">https://icanhazdadjoke.com/</a>, because -there is no authentication and no rate-limiting (two concepts we will cover in another post).</p> -<p>Calling the API is extremely simple:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -</span></span></code></pre></div><p>However, this results in the content being returned as plain text. This isn&rsquo;t ideal.</p> -<p>Let&rsquo;s pass the &lsquo;Accept&rsquo; header to tell the API the format we are expecting to be returned:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers -</span></span></code></pre></div><p>Output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>[<span style="color:#ae81ff">15</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">04</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">34</span>] C:\..\..\rnemeth90.github.io on <span style="color:#960050;background-color:#1e0010"></span>main <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#ae81ff">+1</span> <span style="color:#960050;background-color:#1e0010">❯</span> Invoke-RestMethod -Uri $url -Method Get -Headers $headers -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>id joke status -</span></span><span style="display:flex;"><span>-- ---- ------ -</span></span><span style="display:flex;"><span>3LmyXvsPfqc I don<span style="color:#e6db74">&#39;t trust stairs. They&#39;</span>re always up to something. <span style="color:#ae81ff">200</span> -</span></span></code></pre></div><p>That looks a little better. For those of you familiar with Powershell, the output above probably -looks completely normal. But for those not-so-familiar with Powershell, or those expecting -more of a &lsquo;json-esk&rsquo; output, this may look a bit&hellip; weird.</p> -<p>Powershell is an object oriented language. <strong>Everything is an object</strong> in Powershell, even the response -of this request. What you see in the output is simply the properties of the object.</p> -<p>Luckily Powershell provides us with a cmdlet to convert an object into json (aptly named: ConvertTo-Json). We can use it like this:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers | ConvertTo-Json -</span></span></code></pre></div><p>Here we are piping the output from Invoke-RestMethod to ConvertTo-Json. Pretty neat!</p> -<p>Output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>[<span style="color:#ae81ff">15</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">04</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">35</span>] C:\..\..\rnemeth90.github.io on <span style="color:#960050;background-color:#1e0010"></span>main <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#ae81ff">+1</span> <span style="color:#960050;background-color:#1e0010">❯</span> Invoke-RestMethod -Uri $url -Method Get -Headers $headers | Convertto-json -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;id&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#e6db74">&#34;AAdFBXnGlyd&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;joke&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#e6db74">&#34;If you walk into a forest and cut down a tree, but the tree doesn&#39;t understand why you cut it down, do you think it&#39;s stumped?&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;status&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#ae81ff">200</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Now, that looks more normal.</p> -<p>There is much more we can do with Invoke-RestMethod. The &lsquo;Method&rsquo; parameter of this cmdlet accepts any of the common -HTTP methods (GET, PUT, PATCH, DELETE, POST, HEAD). You can also specify other headers and a body (using the -body parameter).</p> -<p>Both of these parameters accept dictionaries:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Host&#39;</span> = <span style="color:#e6db74">&#39;MyServer&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>$body = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Eat&#39;</span> = <span style="color:#e6db74">&#39;Pizza&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers -Body $body | ConvertTo-Json -</span></span></code></pre></div><p>Unfortunately I won&rsquo;t be able to show the other HTTP methods, as this API only supports GET requests. So that&rsquo;s all for now.</p> - + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ + This will be a short post on querying REST APIs with Powershell. It&rsquo;s hard to argue that REST APIs are the predominant technology for interacting with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) product without having to go through the exercise of a more complicated integration. REST APIs communicate in a common format, typically JSON. However, most will allow us to choose the response format by specifying an option in the &lsquo;Accept&rsquo; header. - Remove Kubernetes Namespace Stuck in the Terminating State - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ Sat, 04 Jun 2022 18:29:41 +0000 - - https://rnemeth90.github.io/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ - <p>In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state.</p> -<p>A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. One day, you decide you no longer want this blog, so you plan to delete it. Rather than tediously deleting all of the various entities associated with this blog, you can delete the namespace that contains these entities. This will essentially ‘cascade delete’ the resources within the namespace as well.</p> -<p>After deleting the namespace for your blog, you notice that it still exists, but the state of it is ‘Terminating’, and it has been like this for a long time (hours or maybe even days).</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2022/06/image.png"></a></p> -<p>Kubernetes will occassionally fail to delete third-party resources when deleting a namespace, causing the namespace to linger. This can happen if the third-party API managing the resource is not responding to requests. To verify if any of these resources still exist, use this command:</p> -<pre tabindex="0"><code>kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get --show-kind --show-all --ignore-not-found -n &lt;terminating-namespace&gt; -</code></pre><p>If you happen to see any resources in the output, you can try force deleting them and then try to delete the namespace again.</p> -<p>In my experience, the majority of the time you will not find any resources still hanging around. Rather, the namespace will be completely empty. What is going on here?</p> -<p>Let’s take a look at the namespace:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ae81ff">$ kubectl get namespace darn-c101 -o yaml</span> -</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Namespace</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">annotations</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">kubectl.kubernetes.io/last-applied-configuration</span>: <span style="color:#ae81ff">|</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">kubernetes.io/metadata.name</span>: <span style="color:#ae81ff">darn-c101</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">finalizers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">kubernetes</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">status</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">conditions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">lastTransitionTime</span>: <span style="color:#e6db74">&#34;2022-06-01T19:05:31Z&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">message: &#39;Some content in the namespace has finalizers remaining</span>: <span style="color:#ae81ff">darn-c101.geekyryan.io/finalizer in 1 resource instances&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">reason</span>: <span style="color:#ae81ff">SomeFinalizersRemain</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">status</span>: <span style="color:#e6db74">&#34;True&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">NamespaceFinalizersRemaining</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">phase</span>: <span style="color:#ae81ff">Terminating</span> -</span></span></code></pre></div><p>Notice the inclusion of the finalizers field in the above JSON. Some namespaces have a finalizer defined under spec.</p> -<p>A finalizer is a special metadata key that tells Kubernetes to wait until a specific condition is met before it fully deletes a resource. Much like a finalizer in the .NET framework (does Java have those too? 😀 )</p> -<p>So when you run a command like <code>kubectl delete namespace &lt;namespace&gt;</code>, Kubernetes checks for a finalizer in the <code>metadata.finalizers</code> field. If the resource defined in the finalizer cannot be deleted, then the namespace is not deleted either. This puts the namespace into a perpetual terminating state and is never actually deleted.</p> -<p>When an object has been terminating for an excessive time, check its finalizers by inspecting the <code>metadata.finalizers</code> field in its YAML.</p> -<p>So we now know what the problem is. How can we solve it? Well, it’s actually quite simple. If you are using bash, use this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> -</span></span><span style="display:flex;"><span>namespaces<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>kubectl get ns --field-selector<span style="color:#f92672">=</span>status.phase<span style="color:#f92672">==</span>Terminating -o jsonpath<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;{range .items[*]}{.metadata.name}{&#34;\n&#34;}{end}&#39;</span><span style="color:#66d9ef">)</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -z <span style="color:#e6db74">&#34;</span>$namespaces<span style="color:#e6db74">&#34;</span><span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">then</span> -</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">&#34;No namespaces to delete.&#34;</span> -</span></span><span style="display:flex;"><span> exit -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> namespace in $namespaces -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">do</span> -</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">&#34;[Removing Namespace]: </span>$namespace<span style="color:#e6db74">&#34;</span> -</span></span><span style="display:flex;"><span> kubectl get namespace $namespace -o json | tr -d <span style="color:#e6db74">&#34;\n&#34;</span> | sed <span style="color:#e6db74">&#34;s/\&#34;finalizers\&#34;: \[[^]]\+\]/\&#34;finalizers\&#34;: []/&#34;</span> | kubectl replace --raw /api/v1/namespaces/$namespace/finalize -f - &gt; /dev/null 2&gt;&amp;<span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">done</span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span> -</span></span></code></pre></div><p><a href="https://gist.github.com/rnemeth90/e83bb4c8808f0d28412cb40edb2487d3">Delete Terminating Kubernetes Namespaces with Bash (github.com)</a></p> -<p>It will search for any namespace that is stuck in the terminating state and forcefully remove it by removing the finalizers field and then using <code> kubectl replace</code> to commit the change back to the Kube API.</p> -<p>If you prefer Powershell, you can use this script:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$terminatingNamespaces = kubectl get ns --field-selector=status.phase==Terminating -o jsonpath=<span style="color:#e6db74">&#34;{range .items[*]}{.metadata.name}{&#39;\n&#39;}{end}&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($ns <span style="color:#66d9ef">in</span> $terminatingNamespaces) { -</span></span><span style="display:flex;"><span> Write-Verbose <span style="color:#e6db74">&#39;[FOUND]: Forcefully removing $ns&#39;</span> -</span></span><span style="display:flex;"><span> $jsonObj = kubectl get namespace $ns -o json | ConvertFrom-Json | foreach-object { $_.spec.finalizers = @(); $_ } | -</span></span><span style="display:flex;"><span> convertto-json | kubectl replace --raw /api/v1/namespaces/$namespace/finalize <span style="color:#f92672">-f</span> - -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><a href="https://gist.github.com/rnemeth90/19d7de622a5009c1cf908c5d4deb5358">Delete Terminating Kubernetes Namespaces with Powershell (github.com)</a></p> -<p>It does the same thing as the bash script, just in more of a Window-zy way.</p> -<p>It’s that simple. I hope this was helpful. If you have any questions, comments, or concerns, please feel free to reach out.</p> - + http://localhost:1313/posts/2022-06-04-remove-kubernetes-namespace-stuck-in-the-terminating-state/ + In this post, we will discuss how to remove a Kubernetes namespace that is stuck in the ‘terminating’ state. A namespace is like a container. You can use it to store related objects in a Kubernetes environment. Maybe you are hosting a blog in Kubernetes. This blog will likely have a database, a frontend website, a load balancer (service) to spread the incoming traffic among ‘x’ number of frontend containers (pods), and maybe some middle-tier or utility applications. - diff --git a/public/tags/powershell/page/1/index.html b/public/tags/powershell/page/1/index.html index f0e70d56..fef57dec 100644 --- a/public/tags/powershell/page/1/index.html +++ b/public/tags/powershell/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/powershell/ - + http://localhost:1313/tags/powershell/ + - + diff --git a/public/tags/programming/index.html b/public/tags/programming/index.html index 21569df1..21fe58b4 100644 --- a/public/tags/programming/index.html +++ b/public/tags/programming/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Programming · GeekyRyan + - - -Programming - GeekyRyan - - - + - - - + + + - - + + + + + + + + + - + + + + - - - - - - - - - - - - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,442 +79,166 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - + + + - - - - - - - - -
    -
    - -

    Tag: Programming

    - - - -
    -
    -
    -

    Use “replace” in go.mod to Point to a Local Module

    -
    - -
    - - -
    - If you want to the local version of a dependency in Go rather than one in a remote repository, use the replace keyword. -The replace line goes above your require statements, like so: -module github.com/rnemeth90/foo replace github.com/rnemeth90/bar => /Users/rnemeth90/Projects/bar require ( github.com/rnemeth90/bar v1.0.0 ) Now when you compile this module go build or go install, it will use your local code rather than the remote dependency. -According to the docs, you do need to make sure that the code you’re pointing to also has a go. -
    - - -
    - Read more -
    - - - +
    + + + +
    +
  • + 2022-07-21 + Reading Json Files with Go +
  • -
    -
    -
    -

    Powershell for Devops - Querying REST APIs with Powershell

    -
    - -
    + + - -
    - This will be a short post on querying REST APIs with Powershell. -It’s hard to argue that REST APIs are the predominant technology for interacting with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) product without having to go through the exercise of a more complicated integration. REST APIs communicate in a common format, typically JSON. However, most will allow us to choose the response format by specifying an option in the ‘Accept’ header. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Reading Json Files with Go

    -
    -
    +
    +
    + © -
    - JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting with it, and most public APIs accept JSON in HTTP requests. -In this post, we’ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the JSON data within the file into a memory structure. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - +
    +
    +
    - + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/tags/programming/index.xml b/public/tags/programming/index.xml index 2a5af542..8118bcb7 100644 --- a/public/tags/programming/index.xml +++ b/public/tags/programming/index.xml @@ -2,218 +2,32 @@ Programming on GeekyRyan - https://rnemeth90.github.io/tags/programming/ - GeekyRyan (Programming) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/programming/ + Recent content in Programming on GeekyRyan + Hugo + en Tue, 06 Sep 2022 00:00:00 +0000 - - - - + Use “replace” in go.mod to Point to a Local Module - https://rnemeth90.github.io/posts/2022-09-06-go-mod-replace-copy/ + http://localhost:1313/posts/2022-09-06-go-mod-replace-copy/ Tue, 06 Sep 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-09-06-go-mod-replace-copy/ - <p>If you want to the local version of a dependency in Go rather than one in a remote repository, use the <em>replace</em> keyword.</p> -<p>The replace line goes above your require statements, like so:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> module github.com/rnemeth90/foo -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> replace github.com/rnemeth90/bar <span style="color:#f92672">=</span>&gt; /Users/rnemeth90/Projects/bar -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> require <span style="color:#f92672">(</span> -</span></span><span style="display:flex;"><span> github.com/rnemeth90/bar v1.0.0 -</span></span><span style="display:flex;"><span> <span style="color:#f92672">)</span> -</span></span></code></pre></div><p>Now when you compile this module <em>go build</em> or <em>go install</em>, it will use your local code rather than the remote dependency.</p> -<p>According to the docs, you do need to make sure that the code you’re pointing to also has a <strong>go.mod</strong> file:</p> -<blockquote> -<p><strong>Note</strong>: if the right-hand side of a <code>replace</code> directive is a filesystem path, then the target must have a <code>go.mod</code> file at that location. If the <code>go.mod</code> file is not present, you can create one with <code>go mod init</code>.</p> -<p><a href="https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive">https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive</a></p> -</blockquote> -<p>You can also create this line from the command line using the <strong>go mod edit</strong> command.</p> -<pre><code>$ go mod edit -replace github.com/rnemeth90/bar=/Users/rnemeth90/Projects/bar -</code></pre> -<p>Following the <strong>-replace</strong> is first what you want to replace, then an equals sign, then what you’re replacing it with.</p> -<p>Hopefully this helps someone who was stuck with this like me 🙂</p> - + http://localhost:1313/posts/2022-09-06-go-mod-replace-copy/ + If you want to the local version of a dependency in Go rather than one in a remote repository, use the replace keyword. The replace line goes above your require statements, like so: module github.com/rnemeth90/foo replace github.com/rnemeth90/bar =&gt; /Users/rnemeth90/Projects/bar require ( github.com/rnemeth90/bar v1.0.0 ) Now when you compile this module go build or go install, it will use your local code rather than the remote dependency. According to the docs, you do need to make sure that the code you’re pointing to also has a go. - Powershell for Devops - Querying REST APIs with Powershell - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ Thu, 04 Aug 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ - <p>This will be a short post on querying REST APIs with Powershell.</p> -<p>It&rsquo;s hard to argue that REST APIs are the predominant technology for interacting -with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) -product without having to go through the exercise of a more complicated integration. REST APIs communicate -in a common format, typically JSON. However, most will allow us to choose the response format by specifying an -option in the &lsquo;Accept&rsquo; header. Most languages provide a native method for interacting with -REST APIs. This objective for this post is to show you how simple this is with Powershell.</p> -<p>To get started, we&rsquo;ll need a public API to interact with. I&rsquo;m going to use <a href="https://icanhazdadjoke.com/">https://icanhazdadjoke.com/</a>, because -there is no authentication and no rate-limiting (two concepts we will cover in another post).</p> -<p>Calling the API is extremely simple:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -</span></span></code></pre></div><p>However, this results in the content being returned as plain text. This isn&rsquo;t ideal.</p> -<p>Let&rsquo;s pass the &lsquo;Accept&rsquo; header to tell the API the format we are expecting to be returned:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers -</span></span></code></pre></div><p>Output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>[<span style="color:#ae81ff">15</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">04</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">34</span>] C:\..\..\rnemeth90.github.io on <span style="color:#960050;background-color:#1e0010"></span>main <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#ae81ff">+1</span> <span style="color:#960050;background-color:#1e0010">❯</span> Invoke-RestMethod -Uri $url -Method Get -Headers $headers -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>id joke status -</span></span><span style="display:flex;"><span>-- ---- ------ -</span></span><span style="display:flex;"><span>3LmyXvsPfqc I don<span style="color:#e6db74">&#39;t trust stairs. They&#39;</span>re always up to something. <span style="color:#ae81ff">200</span> -</span></span></code></pre></div><p>That looks a little better. For those of you familiar with Powershell, the output above probably -looks completely normal. But for those not-so-familiar with Powershell, or those expecting -more of a &lsquo;json-esk&rsquo; output, this may look a bit&hellip; weird.</p> -<p>Powershell is an object oriented language. <strong>Everything is an object</strong> in Powershell, even the response -of this request. What you see in the output is simply the properties of the object.</p> -<p>Luckily Powershell provides us with a cmdlet to convert an object into json (aptly named: ConvertTo-Json). We can use it like this:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers | ConvertTo-Json -</span></span></code></pre></div><p>Here we are piping the output from Invoke-RestMethod to ConvertTo-Json. Pretty neat!</p> -<p>Output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>[<span style="color:#ae81ff">15</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">04</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">35</span>] C:\..\..\rnemeth90.github.io on <span style="color:#960050;background-color:#1e0010"></span>main <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#ae81ff">+1</span> <span style="color:#960050;background-color:#1e0010">❯</span> Invoke-RestMethod -Uri $url -Method Get -Headers $headers | Convertto-json -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;id&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#e6db74">&#34;AAdFBXnGlyd&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;joke&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#e6db74">&#34;If you walk into a forest and cut down a tree, but the tree doesn&#39;t understand why you cut it down, do you think it&#39;s stumped?&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;status&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#ae81ff">200</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Now, that looks more normal.</p> -<p>There is much more we can do with Invoke-RestMethod. The &lsquo;Method&rsquo; parameter of this cmdlet accepts any of the common -HTTP methods (GET, PUT, PATCH, DELETE, POST, HEAD). You can also specify other headers and a body (using the -body parameter).</p> -<p>Both of these parameters accept dictionaries:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Host&#39;</span> = <span style="color:#e6db74">&#39;MyServer&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>$body = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Eat&#39;</span> = <span style="color:#e6db74">&#39;Pizza&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers -Body $body | ConvertTo-Json -</span></span></code></pre></div><p>Unfortunately I won&rsquo;t be able to show the other HTTP methods, as this API only supports GET requests. So that&rsquo;s all for now.</p> - + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ + This will be a short post on querying REST APIs with Powershell. It&rsquo;s hard to argue that REST APIs are the predominant technology for interacting with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) product without having to go through the exercise of a more complicated integration. REST APIs communicate in a common format, typically JSON. However, most will allow us to choose the response format by specifying an option in the &lsquo;Accept&rsquo; header. - Reading Json Files with Go - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ + http://localhost:1313/posts/2022-07-21-reading-json-files-with-go/ Thu, 21 Jul 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ - <p>JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting -with it, and most public APIs accept JSON in HTTP requests.</p> -<p>In this post, we&rsquo;ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the -JSON data within the file into a memory structure.</p> -<p>Let&rsquo;s assume we have the following JSON data representing an employee:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">1</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Steve&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Rogers&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Captain America&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Department&#34;</span>: <span style="color:#e6db74">&#34;Avengers&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>We need a way of representing this data in memory when decoding it from JSON. For this, we will need to create a struct:</p> -<p>We will build up our go module as we progress through the article</p> -<p>Let&rsquo;s start:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#75715e">// main.go -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> ( -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;encoding/json&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;fmt&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;io/ioutil&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;log&#34;</span> -</span></span><span style="display:flex;"><span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">// Hero represents an hero -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// ALL fields must be exportable! Otherwise the JSON parsing will fail. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Hero</span> <span style="color:#66d9ef">struct</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Id</span> <span style="color:#66d9ef">int</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">FirstName</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">LastName</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Alias</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Group</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() { -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Here we set the log prefix. When reading stack traces, this makes it easier to know -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// where a failure occurred. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">SetPrefix</span>(<span style="color:#e6db74">&#34;main(): &#34;</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// We first need to load the JSON file into memory -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">content</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">ioutil</span>.<span style="color:#a6e22e">ReadFile</span>(<span style="color:#e6db74">&#34;./heros.json&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#e6db74">&#34;Error opening the file: &#34;</span>, <span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Now we parse the JSON data into a memory structure. We know our JSON file will have more than one hero object, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// so we&#39;ll use make() to create a []Hero slice. Since go is a pass-by-value language, we will then use the address-of -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// operator (&amp;) to unmarshal our json data into the heros slice -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">heros</span> <span style="color:#f92672">:=</span> make([]<span style="color:#a6e22e">Hero</span>, <span style="color:#ae81ff">5</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">json</span>.<span style="color:#a6e22e">Unmarshal</span>(<span style="color:#a6e22e">content</span>, <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">heros</span>) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#e6db74">&#34;Error occurred during unmarshal: &#34;</span>, <span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// now we can read/interact with the data. We&#39;ll loop over the array -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// and print the values in memory -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; len(<span style="color:#a6e22e">heros</span>); <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">Id</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">FirstName</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">LastName</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">Group</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Create a file named employees.json with similar data:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>[ -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">1</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Steve&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Rogers&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Captain America&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;group&#34;</span>: <span style="color:#e6db74">&#34;Avengers&#34;</span> -</span></span><span style="display:flex;"><span> }, -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">2</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Clark&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Kent&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Superman&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;group&#34;</span>: <span style="color:#e6db74">&#34;Justice League&#34;</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>] -</span></span></code></pre></div><p>Now, we can run our main.go file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>11:40:47 ryan@xerxes json → go run main.go -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>Steve -</span></span><span style="display:flex;"><span>Rogers -</span></span><span style="display:flex;"><span>Avengers -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span>Clark -</span></span><span style="display:flex;"><span>Kent -</span></span><span style="display:flex;"><span>Justice League -</span></span><span style="display:flex;"><span>11:40:49 ryan@xerxes json -</span></span></code></pre></div><p>Pretty simple! That&rsquo;s why I love go. We accomplished all of this with ~50 lines of code. -Doing something similar in asp.net project would easily double that count and involve creating -multiple files! (nothing against asp.net or c#, I think c# is a great language and use it daily)</p> -<p>Now, &lsquo;go&rsquo; try this!</p> - + http://localhost:1313/posts/2022-07-21-reading-json-files-with-go/ + JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting with it, and most public APIs accept JSON in HTTP requests. In this post, we&rsquo;ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the JSON data within the file into a memory structure. - diff --git a/public/tags/programming/page/1/index.html b/public/tags/programming/page/1/index.html index c7ffcea6..a4a06549 100644 --- a/public/tags/programming/page/1/index.html +++ b/public/tags/programming/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/programming/ - + http://localhost:1313/tags/programming/ + - + diff --git a/public/tags/rest/index.html b/public/tags/rest/index.html index 53bc8644..10409561 100644 --- a/public/tags/rest/index.html +++ b/public/tags/rest/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Rest · GeekyRyan + - - -rest - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,301 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Tag: rest

    - - - -
    -
    -
    -

    Powershell for Devops - Querying REST APIs with Powershell

    -
    -
    +
    +
    + © -
    - This will be a short post on querying REST APIs with Powershell. -It’s hard to argue that REST APIs are the predominant technology for interacting with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) product without having to go through the exercise of a more complicated integration. REST APIs communicate in a common format, typically JSON. However, most will allow us to choose the response format by specifying an option in the ‘Accept’ header. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/rest/index.xml b/public/tags/rest/index.xml index a0639e48..6fb16838 100644 --- a/public/tags/rest/index.xml +++ b/public/tags/rest/index.xml @@ -1,83 +1,19 @@ - rest on GeekyRyan - https://rnemeth90.github.io/tags/rest/ - GeekyRyan (rest) - Hugo -- gohugo.io - en-us + Rest on GeekyRyan + http://localhost:1313/tags/rest/ + Recent content in Rest on GeekyRyan + Hugo + en Thu, 04 Aug 2022 00:00:00 +0000 - - - - + Powershell for Devops - Querying REST APIs with Powershell - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ Thu, 04 Aug 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ - <p>This will be a short post on querying REST APIs with Powershell.</p> -<p>It&rsquo;s hard to argue that REST APIs are the predominant technology for interacting -with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) -product without having to go through the exercise of a more complicated integration. REST APIs communicate -in a common format, typically JSON. However, most will allow us to choose the response format by specifying an -option in the &lsquo;Accept&rsquo; header. Most languages provide a native method for interacting with -REST APIs. This objective for this post is to show you how simple this is with Powershell.</p> -<p>To get started, we&rsquo;ll need a public API to interact with. I&rsquo;m going to use <a href="https://icanhazdadjoke.com/">https://icanhazdadjoke.com/</a>, because -there is no authentication and no rate-limiting (two concepts we will cover in another post).</p> -<p>Calling the API is extremely simple:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -</span></span></code></pre></div><p>However, this results in the content being returned as plain text. This isn&rsquo;t ideal.</p> -<p>Let&rsquo;s pass the &lsquo;Accept&rsquo; header to tell the API the format we are expecting to be returned:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers -</span></span></code></pre></div><p>Output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>[<span style="color:#ae81ff">15</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">04</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">34</span>] C:\..\..\rnemeth90.github.io on <span style="color:#960050;background-color:#1e0010"></span>main <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#ae81ff">+1</span> <span style="color:#960050;background-color:#1e0010">❯</span> Invoke-RestMethod -Uri $url -Method Get -Headers $headers -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>id joke status -</span></span><span style="display:flex;"><span>-- ---- ------ -</span></span><span style="display:flex;"><span>3LmyXvsPfqc I don<span style="color:#e6db74">&#39;t trust stairs. They&#39;</span>re always up to something. <span style="color:#ae81ff">200</span> -</span></span></code></pre></div><p>That looks a little better. For those of you familiar with Powershell, the output above probably -looks completely normal. But for those not-so-familiar with Powershell, or those expecting -more of a &lsquo;json-esk&rsquo; output, this may look a bit&hellip; weird.</p> -<p>Powershell is an object oriented language. <strong>Everything is an object</strong> in Powershell, even the response -of this request. What you see in the output is simply the properties of the object.</p> -<p>Luckily Powershell provides us with a cmdlet to convert an object into json (aptly named: ConvertTo-Json). We can use it like this:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers | ConvertTo-Json -</span></span></code></pre></div><p>Here we are piping the output from Invoke-RestMethod to ConvertTo-Json. Pretty neat!</p> -<p>Output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>[<span style="color:#ae81ff">15</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">04</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">35</span>] C:\..\..\rnemeth90.github.io on <span style="color:#960050;background-color:#1e0010"></span>main <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#ae81ff">+1</span> <span style="color:#960050;background-color:#1e0010">❯</span> Invoke-RestMethod -Uri $url -Method Get -Headers $headers | Convertto-json -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;id&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#e6db74">&#34;AAdFBXnGlyd&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;joke&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#e6db74">&#34;If you walk into a forest and cut down a tree, but the tree doesn&#39;t understand why you cut it down, do you think it&#39;s stumped?&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;status&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#ae81ff">200</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Now, that looks more normal.</p> -<p>There is much more we can do with Invoke-RestMethod. The &lsquo;Method&rsquo; parameter of this cmdlet accepts any of the common -HTTP methods (GET, PUT, PATCH, DELETE, POST, HEAD). You can also specify other headers and a body (using the -body parameter).</p> -<p>Both of these parameters accept dictionaries:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Host&#39;</span> = <span style="color:#e6db74">&#39;MyServer&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>$body = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Eat&#39;</span> = <span style="color:#e6db74">&#39;Pizza&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers -Body $body | ConvertTo-Json -</span></span></code></pre></div><p>Unfortunately I won&rsquo;t be able to show the other HTTP methods, as this API only supports GET requests. So that&rsquo;s all for now.</p> - + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ + This will be a short post on querying REST APIs with Powershell. It&rsquo;s hard to argue that REST APIs are the predominant technology for interacting with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) product without having to go through the exercise of a more complicated integration. REST APIs communicate in a common format, typically JSON. However, most will allow us to choose the response format by specifying an option in the &lsquo;Accept&rsquo; header. - diff --git a/public/tags/rest/page/1/index.html b/public/tags/rest/page/1/index.html index bd34f913..8c6db81a 100644 --- a/public/tags/rest/page/1/index.html +++ b/public/tags/rest/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/rest/ - + http://localhost:1313/tags/rest/ + - + diff --git a/public/tags/scripts/index.html b/public/tags/scripts/index.html index b4eb979d..a6c112b8 100644 --- a/public/tags/scripts/index.html +++ b/public/tags/scripts/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Scripts · GeekyRyan + - - -Scripts - GeekyRyan + - + + + - - - + + + - + + + + + + - - - + + + + - - - - - - - - - - - - - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,535 +79,176 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - - -
    -
    - -

    Tag: Scripts

    - - - -
    -
    -
    -

    Script to Move All Disabled AD Objects to a Specified OU

    -
    - -
    - - -
    - The title says it all. This script will move all disabled AD objects to a specified OU. This script accepts parameters that will allow you to specify whether you want to move Users or Computers and the destination OU. It also accepts a “test mode” parameter that will run the script and output the results, without actually modifying Active Directory. -This is revision 1 of the script. There are still several improvements I would like to make, including better error handling and recovery. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Script for Setting the License for Multiple Office 365 User Accounts

    -
    - -
    - - -
    - A script for setting the Office 365 license for multiple users. Requires a CSV file named users.csv. This file must in the same directory as the script. The CSV file must contain three columns. The title of the columns should be UPN, UsageLocation, and SKU. -BulkSet-MsolUserLicense.ps1 -
    - - - - - - - - -
    - -
    -
    -
    -

    Script for Querying All AD Computers Time Source

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Tag: Scripts +

    +
    + +
    +
  • + 2014-12-08 + Powershell: SID to Username +
  • -
    -
    -
    -

    Ping Sweeping with FPing

    -
    - -
    + + - -
    - I generally use NMAP for any type of host discovery, but recently started experimenting with FPing. One thing I found is that, when performing a ping sweep, not only do I see the hosts that replied to the ping, but FPing also sends any unreachable IP addresses to stdout (which is super annoying and ugly if you ask me…). -Anyway, after a bit of research, I found a nifty way to suppress these messages. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Powershell: SID to Username

    -
    -
    +
    +
    + © -
    - This is a simple script to convert a SID to a username -# Returns a username based on a SID # Author: Ryan Nemeth # Date: 12/2/2014 $SID = read-host “Please enter the SID: ” $object = New-Object System.Security.Principal.SecurityIdentifier($SID) $User = $object.Translate( \[System.Security.Principal.NTAccount\]) write-host “The user is: ” $User.Value -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - +
    +
    -
    - https://rnemeth90.github.io/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/scripts/index.xml b/public/tags/scripts/index.xml index 3ab83645..1f93cd28 100644 --- a/public/tags/scripts/index.xml +++ b/public/tags/scripts/index.xml @@ -2,114 +2,46 @@ Scripts on GeekyRyan - https://rnemeth90.github.io/tags/scripts/ - GeekyRyan (Scripts) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/scripts/ + Recent content in Scripts on GeekyRyan + Hugo + en Thu, 06 Oct 2016 03:03:00 +0000 - - - - + Script to Move All Disabled AD Objects to a Specified OU - https://rnemeth90.github.io/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ + http://localhost:1313/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ Thu, 06 Oct 2016 03:03:00 +0000 - - https://rnemeth90.github.io/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ - <p>The title says it all. This script will move all disabled AD objects to a specified OU. This script accepts parameters that will allow you to specify whether you want to move Users or Computers and the destination OU. It also accepts a “test mode” parameter that will run the script and output the results, without actually modifying Active Directory.</p> -<p>This is revision 1 of the script. There are still several improvements I would like to make, including better error handling and recovery.</p> -<p>If you have any suggestions or requests, please leave a comment.</p> -<p><a href="https://drive.google.com/open?id=0B2K6VOnt6zeXMVFleWZISHZBTnc">Download Here</a></p> - + http://localhost:1313/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ + The title says it all. This script will move all disabled AD objects to a specified OU. This script accepts parameters that will allow you to specify whether you want to move Users or Computers and the destination OU. It also accepts a “test mode” parameter that will run the script and output the results, without actually modifying Active Directory. This is revision 1 of the script. There are still several improvements I would like to make, including better error handling and recovery. - Script for Setting the License for Multiple Office 365 User Accounts - https://rnemeth90.github.io/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ + http://localhost:1313/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ Mon, 11 Apr 2016 01:25:00 +0000 - - https://rnemeth90.github.io/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ - <p>A script for setting the Office 365 license for multiple users. Requires a CSV file named users.csv. This file must in the same directory as the script. The CSV file must contain three columns. The title of the columns should be UPN, UsageLocation, and SKU.</p> -<p><a href="https://drive.google.com/open?id=0B2K6VOnt6zeXZ2Z6OFZhZVoyenc">BulkSet-MsolUserLicense.ps1</a></p> - + http://localhost:1313/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ + A script for setting the Office 365 license for multiple users. Requires a CSV file named users.csv. This file must in the same directory as the script. The CSV file must contain three columns. The title of the columns should be UPN, UsageLocation, and SKU. BulkSet-MsolUserLicense.ps1 - Script for Querying All AD Computers Time Source - https://rnemeth90.github.io/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ + http://localhost:1313/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ Tue, 01 Sep 2015 21:05:00 +0000 - - https://rnemeth90.github.io/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ - <p>This script will iterate through all computers in Active Directory and return the configured time server for each computer.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span><span style="color:#75715e">&lt;# -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">SYNOPSIS</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Get time source for all computers in domain -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">EXAMPLE</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Get-TimeSource -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">NOTES</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Author: Ryan Nemeth - RyanNemeth@live.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Site: http://www.geekyryan.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">LINK</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> http://www.geekyryan.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">DESCRIPTION</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> This function will iterate through all computers/servers in a domain and return the time source -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> for each. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#&gt;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Write-Host -foregroundcolor Red -BackgroundColor black <span style="color:#e6db74">&#34;This script must be run on a domain controller and requires that the AD Powershell module be installed&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$module = Get-Module -ListAvailable | Select-Object -ExpandProperty Name -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span>($module <span style="color:#f92672">-notcontains</span> <span style="color:#e6db74">&#34;ActiveDirectory&#34;</span>) { -</span></span><span style="display:flex;"><span> Write-Host -foregroundcolor red -backgroundcolor black <span style="color:#e6db74">&#34;***Active Directory Powershell Module Not Found***&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span> { -</span></span><span style="display:flex;"><span> Write-Host -foregroundcolor yellow <span style="color:#e6db74">&#34;Found Active Directory Powershell Module. Importing...&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Import-Module ActiveDirectory -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$computers = get-adcomputer -filter * | Select-Object -ExpandProperty Name -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span>($computer <span style="color:#66d9ef">in</span> $computers) { -</span></span><span style="display:flex;"><span> $tm_source = w32tm /query /computer<span style="color:#960050;background-color:#1e0010">:</span>$computer /source -</span></span><span style="display:flex;"><span> write-host <span style="color:#e6db74">&#34;The time source for&#34;</span> $computer <span style="color:#e6db74">&#34;is&#34;</span> $tm_source -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><img src="https://github.com/rnemeth90/PowerShell/blob/master/NTP/Get-TimeSource.ps1" alt=""></p> - + http://localhost:1313/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ + This script will iterate through all computers in Active Directory and return the configured time server for each computer. &lt;# .SYNOPSIS Get time source for all computers in domain .EXAMPLE Get-TimeSource .NOTES Author: Ryan Nemeth - RyanNemeth@live.com Site: http://www.geekyryan.com .LINK http://www.geekyryan.com .DESCRIPTION This function will iterate through all computers/servers in a domain and return the time source for each. #&gt; Write-Host -foregroundcolor Red -BackgroundColor black &#34;This script must be run on a domain controller and requires that the AD Powershell module be installed&#34; $module = Get-Module -ListAvailable | Select-Object -ExpandProperty Name if($module -notcontains &#34;ActiveDirectory&#34;) { Write-Host -foregroundcolor red -backgroundcolor black &#34;***Active Directory Powershell Module Not Found***&#34; } else { Write-Host -foregroundcolor yellow &#34;Found Active Directory Powershell Module. - Ping Sweeping with FPing - https://rnemeth90.github.io/posts/2015-03-09-ping-sweeping-with-fping/ + http://localhost:1313/posts/2015-03-09-ping-sweeping-with-fping/ Mon, 09 Mar 2015 01:08:00 +0000 - - https://rnemeth90.github.io/posts/2015-03-09-ping-sweeping-with-fping/ - <p>I generally use NMAP for any type of host discovery, but recently started experimenting with FPing. One thing I found is that, when performing a ping sweep, not only do I see the hosts that replied to the ping, but FPing also sends any unreachable IP addresses to stdout (which is super annoying and ugly if you ask me…).</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h04_50.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h04_50.png" alt=""></a></p> -<p>Anyway, after a bit of research, I found a nifty way to suppress these messages. Linux allows us to redirect all error messages to /dev/null. So instead of just running the vanilla fping -a -g…. you would run the program and output all error messages /dev/null, like so:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h07_14.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h07_14.png" alt=""></a></p> - + http://localhost:1313/posts/2015-03-09-ping-sweeping-with-fping/ + I generally use NMAP for any type of host discovery, but recently started experimenting with FPing. One thing I found is that, when performing a ping sweep, not only do I see the hosts that replied to the ping, but FPing also sends any unreachable IP addresses to stdout (which is super annoying and ugly if you ask me…). Anyway, after a bit of research, I found a nifty way to suppress these messages. - Powershell: SID to Username - https://rnemeth90.github.io/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ + http://localhost:1313/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ Mon, 08 Dec 2014 13:43:00 +0000 - - https://rnemeth90.github.io/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ - <p>This is a simple script to convert a SID to a username</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span><span style="color:#75715e"># Returns a username based on a SID</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Author: Ryan Nemeth</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Date: 12/2/2014</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$SID = read-host <span style="color:#960050;background-color:#1e0010">“</span>Please enter the SID<span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#960050;background-color:#1e0010">”</span> -</span></span><span style="display:flex;"><span>$object = New-Object System.Security.Principal.SecurityIdentifier($SID) -</span></span><span style="display:flex;"><span>$User = $object.Translate( \[System.Security.Principal.NTAccount\]) -</span></span><span style="display:flex;"><span>write-host <span style="color:#960050;background-color:#1e0010">“</span>The user is<span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#960050;background-color:#1e0010">”</span> $User.Value -</span></span></code></pre></div> + http://localhost:1313/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ + This is a simple script to convert a SID to a username # Returns a username based on a SID # Author: Ryan Nemeth # Date: 12/2/2014 $SID = read-host “Please enter the SID: ” $object = New-Object System.Security.Principal.SecurityIdentifier($SID) $User = $object.Translate( \[System.Security.Principal.NTAccount\]) write-host “The user is: ” $User.Value - diff --git a/public/tags/scripts/page/1/index.html b/public/tags/scripts/page/1/index.html index 767ac772..2032c746 100644 --- a/public/tags/scripts/page/1/index.html +++ b/public/tags/scripts/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/scripts/ - + http://localhost:1313/tags/scripts/ + - + diff --git a/public/tags/security/index.html b/public/tags/security/index.html index d575aa2e..9651faa5 100644 --- a/public/tags/security/index.html +++ b/public/tags/security/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Security · GeekyRyan + - - -Security - GeekyRyan - - - - - - - - - - + - - + + + - - + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,351 +79,161 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    -
    -
    - -

    Tag: Security

    - + 2020-11-17 + Azure Policy &#8211; Allowed Locations for Resource Deployment + +
  • + 2015-03-09 + Ping Sweeping with FPing +
  • -
    -
    -
    -

    Azure Policy &#8211; Allowed Locations for Resource Deployment

    -
    - -
    + + - -
    - Azure Policy allows us to control what actions users can perform regarding creating and managing resources in Azure. We can define policies for naming standards, require that certain extensions be installed on virtual machines, audit various resources for certain configurations… the possibilities are endless. -In this article, well focus on defining what locations users can deploy resources in. To get started, login to the Azure Portal and search for “Policy”. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Ping Sweeping with FPing

    -
    -
    +
    +
    + © -
    - I generally use NMAP for any type of host discovery, but recently started experimenting with FPing. One thing I found is that, when performing a ping sweep, not only do I see the hosts that replied to the ping, but FPing also sends any unreachable IP addresses to stdout (which is super annoying and ugly if you ask me…). -Anyway, after a bit of research, I found a nifty way to suppress these messages. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - +
    +
    -
    - https://rnemeth90.github.io/posts/2015-03-09-ping-sweeping-with-fping/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/security/index.xml b/public/tags/security/index.xml index d5450605..7fb68377 100644 --- a/public/tags/security/index.xml +++ b/public/tags/security/index.xml @@ -2,57 +2,25 @@ Security on GeekyRyan - https://rnemeth90.github.io/tags/security/ - GeekyRyan (Security) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/security/ + Recent content in Security on GeekyRyan + Hugo + en Tue, 17 Nov 2020 17:52:00 +0000 - - - - + Azure Policy &#8211; Allowed Locations for Resource Deployment - https://rnemeth90.github.io/posts/2020-11-17-azure-policy-allowed-locations-for/ + http://localhost:1313/posts/2020-11-17-azure-policy-allowed-locations-for/ Tue, 17 Nov 2020 17:52:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-17-azure-policy-allowed-locations-for/ - <p>Azure Policy allows us to control what actions users can perform regarding creating and managing resources in Azure. We can define policies for naming standards, require that certain extensions be installed on virtual machines, audit various resources for certain configurations… the possibilities are endless.</p> -<p>In this article, well focus on defining what locations users can deploy resources in. To get started, login to the Azure Portal and search for “Policy”.</p> -<p><a href="https://lh3.googleusercontent.com/-7ao7r-Xj5Kk/X7QNKSrY3AI/AAAAAAAAx-8/xIUtw-pRL20pSMxsOaGUwnk-9XHSpup9ACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-4.png" alt=""></a></p> -<p>Click on “Definitions”. Here you will find several built-in definitions that can be applied to your resources. Definitions are a json template containing the logic for what you want to accomplish. It is worth investing some time to look through these built-in definitions.</p> -<p>In the “search” field, type in “location”. Then, click on the “Allowed Locations” definition.</p> -<p><a href="https://lh3.googleusercontent.com/-5FJ3EcMnG8k/X7QNP-1-5II/AAAAAAAAx_A/TH4cr4SxgbQiNVdoRlDyB_F4ukOV5bJvwCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-5.png" alt=""></a></p> -<p>Here you can see the json content of the definition. The “policyRule” section is the bread and butter of the definition. In this particular example, the policyRule states that if the location that the user is deploying a resource to is NOT a) in the list of allowed locations, b) global, or c) a b2c directory, then deny the deployment.</p> -<p><a href="https://lh3.googleusercontent.com/-WKsYDX4nao4/X7QNVcSEVJI/AAAAAAAAx_E/HIbPqLSHfBIjYRRZI27X7cLjStbnXlqaQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-6.png" alt=""></a></p> -<p>Next, click on “Assign”.</p> -<p><a href="https://lh3.googleusercontent.com/-Qg35QQcnGZY/X7QNarWcMbI/AAAAAAAAx_M/Et9yP9ZNyXEU1Ow8m5BwZG8RcTBaadInQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-7.png" alt=""></a></p> -<p>You can assign the policy to a subscription or resource group. You can also create exclusions in this same window, and enable or disable the policy.</p> -<p><a href="https://lh3.googleusercontent.com/-16qmOT43oKo/X7QNfuX4KVI/AAAAAAAAx_Q/_0wak5v2CCA2yIrwLalJgvhCnBCCEJcOQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-8.png" alt=""></a></p> -<p>Click “Next”, and on the Parameters page, choose the allowed locations from the drop down menu. Then click next.</p> -<p>Azure Policy has the capability to remediate non-compliant resources. An example would be having a policy that requires anti-virus be installed on all servers. If Azure Policy detected a server that did NOT have anti-virus installed, it would use a managed identity to install AV software on the server. This particular policy does not need a remediation action, so we will just click “Next” here.</p> -<p>On the Review + Create window, review the resource and then click “Create”.</p> -<p>Back on the Azure Policy blade, select “Assignments”. We can now see that our new policy is assigned.</p> -<p><a href="https://lh3.googleusercontent.com/-K8ofsNe1ALY/X7QNrf8dfkI/AAAAAAAAx_c/3R0DRk4LKWYcGP6-LJ3vgRUcUOQaZ6r3ACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-9.png" alt=""></a></p> -<p>Back on the “Overview” page, you can track compliance for the policy. We can see here that compliance for the “Allowed Locations” policy assignment has not yet been started. This typically takes an hour or so before the compliance state is updated.</p> -<p><a href="https://lh3.googleusercontent.com/-S-zq_cWBh7Y/X7QNvjMRUrI/AAAAAAAAx_k/CG194fTLqKIHqTNMmCyJzM4W9HJ_d6aPgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-10.png" alt=""></a></p> -<p>Click on the Policy to get a more detailed view of compliance, view the definition, edit the assignment, and even create exemptions.</p> -<p><a href="https://lh3.googleusercontent.com/-9sdnYSeQZ7A/X7QNzt8EEdI/AAAAAAAAx_o/3-2_eyPVjxIFSINg8IzEhKwZzWGUgf9NQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/11/image-11.png" alt=""></a></p> - + http://localhost:1313/posts/2020-11-17-azure-policy-allowed-locations-for/ + Azure Policy allows us to control what actions users can perform regarding creating and managing resources in Azure. We can define policies for naming standards, require that certain extensions be installed on virtual machines, audit various resources for certain configurations… the possibilities are endless. In this article, well focus on defining what locations users can deploy resources in. To get started, login to the Azure Portal and search for “Policy”. - Ping Sweeping with FPing - https://rnemeth90.github.io/posts/2015-03-09-ping-sweeping-with-fping/ + http://localhost:1313/posts/2015-03-09-ping-sweeping-with-fping/ Mon, 09 Mar 2015 01:08:00 +0000 - - https://rnemeth90.github.io/posts/2015-03-09-ping-sweeping-with-fping/ - <p>I generally use NMAP for any type of host discovery, but recently started experimenting with FPing. One thing I found is that, when performing a ping sweep, not only do I see the hosts that replied to the ping, but FPing also sends any unreachable IP addresses to stdout (which is super annoying and ugly if you ask me…).</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h04_50.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h04_50.png" alt=""></a></p> -<p>Anyway, after a bit of research, I found a nifty way to suppress these messages. Linux allows us to redirect all error messages to /dev/null. So instead of just running the vanilla fping -a -g…. you would run the program and output all error messages /dev/null, like so:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h07_14.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h07_14.png" alt=""></a></p> - + http://localhost:1313/posts/2015-03-09-ping-sweeping-with-fping/ + I generally use NMAP for any type of host discovery, but recently started experimenting with FPing. One thing I found is that, when performing a ping sweep, not only do I see the hosts that replied to the ping, but FPing also sends any unreachable IP addresses to stdout (which is super annoying and ugly if you ask me…). Anyway, after a bit of research, I found a nifty way to suppress these messages. - diff --git a/public/tags/security/page/1/index.html b/public/tags/security/page/1/index.html index f6fb124f..5804fbc0 100644 --- a/public/tags/security/page/1/index.html +++ b/public/tags/security/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/security/ - + http://localhost:1313/tags/security/ + - + diff --git a/public/tags/software-deployment/index.html b/public/tags/software-deployment/index.html index ee8028e9..d34097b3 100644 --- a/public/tags/software-deployment/index.html +++ b/public/tags/software-deployment/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Software Deployment · GeekyRyan + - - -software deployment - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,295 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Tag: software deployment

    - - - -
    -
    -
    -

    Continuous Deployment Models

    -
    -
    +
    +
    + © -
    - When deploying new software releases to servers or (insert -as-a-service> here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments. -Blue/Green Deployments Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. Instead, it gets deployed to another set of servers (blue) first. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/software-deployment/index.xml b/public/tags/software-deployment/index.xml index b282a2f1..6a63aa38 100644 --- a/public/tags/software-deployment/index.xml +++ b/public/tags/software-deployment/index.xml @@ -1,64 +1,19 @@ - software deployment on GeekyRyan - https://rnemeth90.github.io/tags/software-deployment/ - GeekyRyan (software deployment) - Hugo -- gohugo.io - en-us + Software Deployment on GeekyRyan + http://localhost:1313/tags/software-deployment/ + Recent content in Software Deployment on GeekyRyan + Hugo + en Fri, 14 Jan 2022 19:24:01 +0000 - - - - + Continuous Deployment Models - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ + http://localhost:1313/posts/2022-01-14-continuous-deployment-models/ Fri, 14 Jan 2022 19:24:01 +0000 - - https://rnemeth90.github.io/posts/2022-01-14-continuous-deployment-models/ - <p>When deploying new software releases to servers or (insert -as-a-service&gt; here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments.</p> -<h2 id="bluegreen-deployments" >Blue/Green Deployments -<span> - <a href="#bluegreen-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. Instead, it gets deployed to another set of servers (blue) first. Since the blue servers are not currently serving any traffic for users, the deployment has no impact. However, once the deployment has been completed successfully and tested, users will be directed to the new deployment (blue). You can control all user traffic or a subset of user traffic if your load balancer supports it (referred to as ‘Progressive Exposure’).</p> -<p>The next release will then repeat the same process. Blue would be the current production environment, so you would first deploy to the green servers. This model requires two sets of identical hosts and a load balancer or reverse proxy in front of them. If there are any unexpected issues with the new release, it is straightforward to switch back to the previous release. The disadvantage to this type of model is that it requires having redundant environments (and potentially wasted resources). However, this is less of a concern if using container orchestration platforms such as Kubernetes.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2022/01/2022-01-19_07h57_58-1024x575.png" alt="Blue Green deployment model"></p> -<h2 id="immutable-servers" >Immutable Servers -<span> - <a href="#immutable-servers"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>There is an alternative method of blue/green deployments called “immutable servers”. This method is identical to blue/green deployments as described above. However, after switching user traffic over to the servers with the new release, the old servers are destroyed. They are not used again. This type of model becomes particularly efficient when using a pipeline that is capable of creating servers for you (i.e., Azure DevOps Pipelines)</p> -<h2 id="canary-deployments" >Canary Deployments -<span> - <a href="#canary-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>In a canary deployment, not all users are routed to the new release immediately. Only a limited percentage of users get access to the new release. These users are the canaries. They should be monitored closely, so it is important to be using Not all users are routed to the new release immediately in a canary deployment. Only a limited percentage of users get access to the latest release. These users are the canaries.</p> -<p>Organizations should monitor the canaries closely, so it is essential to be using monitoring software capable of looking at the statistics of a web application from the users’ perspective (for example, Application Insights). The number of canaries can increase until all traffic is directed to the new release over time. The most significant advantage of this method is limited exposure to issues. If a problem appears after the release is deployed, only a small subset of users will experience it. After you fix the issues and redeploy the release, it’s best to select a different group of users to be canaries.</p> -<h2 id="ring-based-deployments" >Ring Based Deployments -<span> - <a href="#ring-based-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>A ring-based deployment has multiple production environments. Each serves a limited number of users, similar to a canary deployment. However, you can have as many production environments as you want with a ring-based deployment. New releases are deployed to the rings one by one over time.</p> -<h2 id="feature-flag-deployments" >Feature Flag Deployments -<span> - <a href="#feature-flag-deployments"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Feature flags are used to expose new features to sets of users slowly. Unlike the other deployment models, they are not implemented in the infrastructure. Instead, they are typically implemented and enabled in code or database. An example would be a feature flag in a database that gives users access to a button on your web page. A developer could enable the flag for a set of users. These users would be able to see the button; other users would not. Feature flags can even toggle bug fixes or performance improvements.</p> -<p>I will cover implementing blue/green deployments in Azure using Azure DevOps and App Services in a future article.</p> - + http://localhost:1313/posts/2022-01-14-continuous-deployment-models/ + When deploying new software releases to servers or (insert -as-a-service&gt; here), it’s a good idea to either deploy the releases in a controlled manner or to have a quick rollback plan. This article will be diving into blue/green deployments, canary deployments, ring-based deployments, and feature tag deployments. Blue/Green Deployments Link to heading Blue/green deployments are a deployment model where a new application version never gets deployed to the production servers (green) directly. - diff --git a/public/tags/software-deployment/page/1/index.html b/public/tags/software-deployment/page/1/index.html index 4836540e..459459e6 100644 --- a/public/tags/software-deployment/page/1/index.html +++ b/public/tags/software-deployment/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/software-deployment/ - + http://localhost:1313/tags/software-deployment/ + - + diff --git a/public/tags/software-development/index.html b/public/tags/software-development/index.html index 5ac1b611..738bb3f2 100644 --- a/public/tags/software-development/index.html +++ b/public/tags/software-development/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Software Development · GeekyRyan + - - -Software Development - GeekyRyan - - - - - - - - - - - + - - + + + - + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,438 +79,181 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - - -
    -
    - -

    Tag: Software Development

    - - - -
    -
    -
    -

    Using try/catch/finally Blocks in PowerShell

    -
    - -
    - - -
    - Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it’s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we’ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn’t crash when the unexpected occurs. -
    + - -
    - Read more -
    - - - - - - - - - -
    +
    + +
    +
    +

    + Tag: Software Development +

    +
    + + + - - +
    + - - -
    -
    -
    -

    Handling Graceful Shutdown in a .NET App Hosted in Kubernetes

    -
    -
    +
    +
    + © -
    - I was recently involved with troubleshooting some API’s hosted in Kubernetes throwing http/502’s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - +
    - + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/tags/software-development/index.xml b/public/tags/software-development/index.xml index a95e77de..681a58e6 100644 --- a/public/tags/software-development/index.xml +++ b/public/tags/software-development/index.xml @@ -2,387 +2,53 @@ Software Development on GeekyRyan - https://rnemeth90.github.io/tags/software-development/ - GeekyRyan (Software Development) - Hugo -- gohugo.io - en-us - Tue, 15 Aug 2023 00:00:00 +0000 - - - - + http://localhost:1313/tags/software-development/ + Recent content in Software Development on GeekyRyan + Hugo + en + Sat, 29 Jun 2024 00:00:00 +0000 + + + Mounting Multiple Kubernetes Secrets into One Directory + http://localhost:1313/posts/2024-06-29-mount-multiple-kubernetes-secrets-into-one-directory/ + Sat, 29 Jun 2024 00:00:00 +0000 + http://localhost:1313/posts/2024-06-29-mount-multiple-kubernetes-secrets-into-one-directory/ + Introduction Link to heading Combining multiple Kubernetes secrets into a single directory can streamline secret management in your applications. This guide walks you through the process of achieving this in Kubernetes, ensuring efficient and organized secret management. Creating Secrets Link to heading First, create your secrets using the kubectl create secret command: kubectl create secret generic secret-one --from-literal=key1=value1 kubectl create secret generic secret-two --from-literal=key2=value2 Each secret can contain multiple key-value pairs, and you can add more secrets as needed. + + + Detecting MIME Types in Go + http://localhost:1313/posts/2024-03-27-golang-detect-file-type/ + Wed, 27 Mar 2024 00:00:00 +0000 + http://localhost:1313/posts/2024-03-27-golang-detect-file-type/ + Introduction Link to heading Knowing the type of a file you&rsquo;re working with is not just a matter of curiosity — it&rsquo;s often a necessity. This is especially true when you&rsquo;re deciding whether or not a particular operation can be carried out on that file. Go, with its comprehensive standard library, offers a straightforward approach to identifying a file&rsquo;s MIME type, ensuring that developers have the tools they need to make informed decisions about file manipulation. + + + Validating URLs with Go + http://localhost:1313/posts/2023-12-12-golang-url-validation/ + Tue, 19 Dec 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-12-12-golang-url-validation/ + Introduction Link to heading In this post, we&rsquo;ll take a quick look at URL validation using Golang. It&rsquo;s common to implement URL validation as a task within a HTTP request pipeline, typically as middleware. There are many different definitions of &ldquo;validation&rdquo;. For the purpose of this article, we will simply validate that a URL conforms to a particular text pattern. I often see people (mistakenly) use URL and URI interchangeably. + Using try/catch/finally Blocks in PowerShell - https://rnemeth90.github.io/posts/2023-08-15-powershell-try-catch/ + http://localhost:1313/posts/2023-08-15-powershell-try-catch/ Tue, 15 Aug 2023 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2023-08-15-powershell-try-catch/ - <p>Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it&rsquo;s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we&rsquo;ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn&rsquo;t crash when the unexpected occurs. We&rsquo;ll then cover the differences in terminating and non-terminating errors and why you should take these into consideration when implementing error handling.</p> -<h2 id="the-try-block" >The Try Block -<span> - <a href="#the-try-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The Try block is where you place the code that might generate an error. Think of it as a protective bubble around your potentially troublesome code. If an error occurs within the Try block, PowerShell will immediately jump to the corresponding Catch block.</p> -<p>Here&rsquo;s a simple example:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><h2 id="the-catch-block" >The Catch Block -<span> - <a href="#the-catch-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>The Catch block is where you can handle the error. PowerShell provides you with a special variable $_ that contains information about the error. You can use this variable to display error messages or even take corrective actions.</p> -<p>In the example above, we&rsquo;re capturing the error generated by attempting to retrieve a nonexistent file. The $_ variable holds the error message, which we&rsquo;re displaying using Write-Host.</p> -<h2 id="the-finally-block" >The Finally Block -<span> - <a href="#the-finally-block"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Now, let&rsquo;s talk about the unsung hero – the Finally block. This block is executed regardless of whether an error occurred or not. It&rsquo;s where you can place cleanup code that ensures your script leaves no trace behind, even in the face of adversity. Some tasks that are commonly done in the finally block are closing database connections, removing temp files, etc. The finally block is completely optional.</p> -<pre tabindex="0"><code> -try { - # Code that might generate an error - # ... -} -catch { - # Code to handle the error - # ... -} -finally { - # Cleanup code here - # ... -} -</code></pre><h2 id="terminatingnon-terminating-errors" >Terminating/non-terminating Errors -<span> - <a href="#terminatingnon-terminating-errors"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>non-terminating errors are any error that will not stop the execution of your script. Most cmdlets in PowerShell are non-terminating. They may output an error, but your script will continue to run. These kinds of errors cannot be caught with a catch block by default. The reason for this is the default <code>ErrorAction</code> in your PowerShell profile, which is set to <code>Continue</code>.</p> -<pre tabindex="0"><code># To show your default error action type -$ErrorActionPreference -</code></pre><p>Let&rsquo;s go back and look at our first example:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><p>If you took the time to run this code, you may have noticed that the <code>Write-Host</code> cmdlet in the <code>catch</code> block was never ran. Why did we get a red error message in our PowerShell console, rather than the text <code>An error occurred: ...</code>? The reason is that the non-existing path isn&rsquo;t a terminating error, and the default <code>ErrorAction</code> is <code>Continue</code>. To catch the error, you will need to change the <code>ErrorAction</code> in your PowerShell console to <code>Stop</code>. This can be done in multiple ways. You can add <code>-ErrorAction Stop</code> to the cmdlet, like this:</p> -<pre tabindex="0"><code>try { - # Code that might generate an error - Get-Item -Path &#34;NonexistentFile.txt&#34; -ErrorAction Stop -} -catch { - # Code to handle the error - Write-Host &#34;An error occurred: $_&#34; -} -</code></pre><p>Or you can change the <code>ErrorActionPreference</code> for the entire script, by adding this to the top of the script:</p> -<pre tabindex="0"><code>$ErrorActionPreference = &#34;Stop&#34; -</code></pre><h2 id="exceptions" >Exceptions -<span> - <a href="#exceptions"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>If you have ever worked with exceptions in C# you can skip this section. In the previous examples, we used simple <code>catch</code> blocks that will catch <em>any</em> error. This is a good start, but we can do better. PowerShell allows you to catch individual exceptions based on the exception type, similar to how C# handles catching exceptions.</p> -<p>Let&rsquo;s look at an example:</p> -<pre tabindex="0"><code>try { - # Attempt to open a non-existent file - $file = Get-Content -Path &#34;NonexistentFile.txt&#34; -} -catch [System.IO.FileNotFoundException] { - Write-Host &#34;Caught a FileNotFoundException: $_&#34; -} -catch { - Write-Host &#34;Caught an exception: $_&#34; -} -</code></pre><p>We now have two <code>catch</code> blocks. If we encounter an exception of type <code>System.IO.FileNotFoundException</code>, the first <code>catch</code> block will catch the exception and handle it accordingly. The second <code>catch</code> block will handle any other generic error.</p> -<h2 id="conclusion" >Conclusion -<span> - <a href="#conclusion"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Error handling might seem daunting at first, but with the power of Try-Catch-Finally blocks at your fingertips, you&rsquo;re well-equipped to handle errors gracefully and ensure the resilience of your PowerShell scripts. Remember, every error is an opportunity to refine your skills and make your scripts more robust.</p> -<p>Thanks for reading!</p> -<p>Official Microsoft Documentation for Try-Catch-Finally in PowerShell: -<a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-7.3">about_try_catch_finally</a></p> - + http://localhost:1313/posts/2023-08-15-powershell-try-catch/ + Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it&rsquo;s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we&rsquo;ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn&rsquo;t crash when the unexpected occurs. - Golang: When Identical Strings are Not Equal - https://rnemeth90.github.io/posts/2023-01-24-golang-strings-not-equal/ + http://localhost:1313/posts/2023-01-24-golang-strings-not-equal/ Tue, 24 Jan 2023 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2023-01-24-golang-strings-not-equal/ - <p><em>This will be a quick and dirty post, so please forgive any spelling/grammar mistakes.</em></p> -<p>I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don&rsquo;t write a ton of code at work (mostly just scripting/pipelines when I do), so I&rsquo;m constantly working on something like this in my spare time. Anyway, I was writing this app, got everything working like I wanted it to. I then wrote some of the tests and was iterating over them. I noticed the <code>ListTasks</code> test was failing:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TestAddTask</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">task</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;test task number 1&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Getwd</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmdPath</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">binaryName</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;AddNewTask&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-add&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">Run</span>(); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// failing test -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;ListTasks&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-list&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">out</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">CombinedOutput</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">expected</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;[ ] 1: %s&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Compare</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#a6e22e">expected</span>) <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;got %v, expected %v\n&#34;</span>, <span style="color:#a6e22e">out</span>, []byte(<span style="color:#a6e22e">expected</span>)) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Seems strange, considering the strings appear to be equivalent in the output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span> main_test.go:82: got <span style="color:#f92672">[</span> <span style="color:#f92672">]</span> 1: test task number <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span> , expected <span style="color:#f92672">[</span> <span style="color:#f92672">]</span> 1: test task number <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>--- FAIL: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- FAIL: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>FAIL -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>exit status <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>FAIL github.com/rnemeth90/todo/cmd/todo 0.105s -</span></span></code></pre></div><p>What could be happening? After banging my head on the desk a few times, a revelation came to me&hellip;</p> -<p>In Go, strings are simply slices of bytes. I decided to print out each string as a byte array:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span> main_test.go:80: got <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">10</span> 10<span style="color:#f92672">]</span>, expected <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> 49<span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span>--- FAIL: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- FAIL: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>FAIL -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>exit status <span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>FAIL github.com/rnemeth90/todo/cmd/todo 0.144s -</span></span></code></pre></div><p>Let&rsquo;s take a closer look at the byte arrays from the test output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>got <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">10</span> 10<span style="color:#f92672">]</span> -</span></span><span style="display:flex;"><span>expected <span style="color:#f92672">[</span><span style="color:#ae81ff">91</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">93</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">49</span> <span style="color:#ae81ff">58</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">116</span> <span style="color:#ae81ff">97</span> <span style="color:#ae81ff">115</span> <span style="color:#ae81ff">107</span> <span style="color:#ae81ff">32</span> <span style="color:#ae81ff">110</span> <span style="color:#ae81ff">117</span> <span style="color:#ae81ff">109</span> <span style="color:#ae81ff">98</span> <span style="color:#ae81ff">101</span> <span style="color:#ae81ff">114</span> <span style="color:#ae81ff">32</span> 49<span style="color:#f92672">]</span> -</span></span></code></pre></div><p>We can see the byte array returned from <code>cmd.CombinedOutput()</code> has some additional bytes in it at the end (32,10,10). What exactly are 32, 10, and 10? To figure this out, I went over to the go playground: <a href="https://go.dev/play/">https://go.dev/play/</a>.</p> -<p>Let&rsquo;s see what happens when we create a byte array with a single number and print it out as a string to the console:</p> -<p><a href="https://rnemeth90.github.io/images/golang-strings-not-equal-01.png"><img src="https://rnemeth90.github.io/images/golang-strings-not-equal-01.png" alt=""></a></p> -<p>Interesting, we can see that <code>m</code> was output to the console. So what do our mysterious additional characters in our test result represent? Let&rsquo;s see:</p> -<p><a href="https://rnemeth90.github.io/images/golang-strings-not-equal-02.png"><img src="https://rnemeth90.github.io/images/golang-strings-not-equal-02.png" alt=""></a></p> -<p>It&rsquo;s hard to tell from the output, but if you look in the results pane, you&rsquo;ll see a space and two new lines. So <code>32</code> represents a space, and <code>10</code> represents a new line!</p> -<p>You can play with this code yourself: <a href="https://go.dev/play/p/fGUIxJM6KnV">https://go.dev/play/p/fGUIxJM6KnV</a></p> -<p>Ok, so let&rsquo;s fix our failing test:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TestAddTask</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">task</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">&#34;test task number 1&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Getwd</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmdPath</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Join</span>(<span style="color:#a6e22e">dir</span>, <span style="color:#a6e22e">binaryName</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;AddNewTask&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-add&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">Run</span>(); <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Run</span>(<span style="color:#e6db74">&#34;ListTasks&#34;</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">cmd</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">exec</span>.<span style="color:#a6e22e">Command</span>(<span style="color:#a6e22e">cmdPath</span>, <span style="color:#e6db74">&#34;-list&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">out</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">cmd</span>.<span style="color:#a6e22e">CombinedOutput</span>() -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// add this line -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">out</span> = []byte(<span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">TrimSuffix</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#e6db74">&#34; \n\n&#34;</span>)) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">expected</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Sprintf</span>(<span style="color:#e6db74">&#34;[ ] 1: %s&#34;</span>, <span style="color:#a6e22e">task</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">strings</span>.<span style="color:#a6e22e">Compare</span>(string(<span style="color:#a6e22e">out</span>), <span style="color:#a6e22e">expected</span>) <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">t</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;got %v, expected %v\n&#34;</span>, <span style="color:#a6e22e">out</span>, []byte(<span style="color:#a6e22e">expected</span>)) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>The <code>strings</code> package has a <code>TrimSuffix</code> function that is useful for trimming bits off the end of a string. In the code above, you can see that we added <code>out = []byte(strings.TrimSuffix(string(out), &quot; \n\n&quot;))</code>, which will trim off the space (character 32) and the two new lines (character 10). Now when we run our integration test, it passes:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>ryan:todo/ |main U:4 ?:1 ✗|$ go test -v -</span></span><span style="display:flex;"><span>Building tool... -</span></span><span style="display:flex;"><span>using /tmp/.testtodo.json -</span></span><span style="display:flex;"><span>running... -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/AddNewTask -</span></span><span style="display:flex;"><span><span style="color:#f92672">===</span> RUN TestAddTask/ListTasks -</span></span><span style="display:flex;"><span>--- PASS: TestAddTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/AddNewTask <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span> --- PASS: TestAddTask/ListTasks <span style="color:#f92672">(</span>0.00s<span style="color:#f92672">)</span> -</span></span><span style="display:flex;"><span>PASS -</span></span><span style="display:flex;"><span>cleaning up... -</span></span><span style="display:flex;"><span>ok github.com/rnemeth90/todo/cmd/todo 0.106s -</span></span></code></pre></div> + http://localhost:1313/posts/2023-01-24-golang-strings-not-equal/ + This will be a quick and dirty post, so please forgive any spelling/grammar mistakes. I was writing a little CLI tool in Golang to track todo items. Just a dumb little app to help hone my skills a bit, but still something useful that serves a purpose to me. I don&rsquo;t write a ton of code at work (mostly just scripting/pipelines when I do), so I&rsquo;m constantly working on something like this in my spare time. - Handling Graceful Shutdown in a .NET App Hosted in Kubernetes - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ Wed, 28 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ - <p>I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. It was actually a combination of these blogs (and the resolutions posted) that ended up resolving our issue.</p> -<h3 id="so-what-was-actually-causing-the-502s" >So what was actually causing the 502&rsquo;s? -<span> - <a href="#so-what-was-actually-causing-the-502s"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h3><p>As stated, these APIs are hosted in Kubernetes. They are written primarily in c# (.NET Framework) and hosted in Windows Server Core containers. The pods are load balanced using a service, and we have an Nginx ingress on top of the service. Nothing fancy, just a typical setup that you may have seen or even built yourself. We implement automatic scaling for our replica sets using a standard Kubernetes-native HPA or Keda, depending on the app. We have autoscale rules defined for the pods. Our clusters are hosted in Azure Kubernetes Service, and we autoscale our node pools. So, there are several layers of scaling happening in our clusters at any given time. Occasionally, when a pod was handling a client request, Kubelet or a controller would come along and scale the pod in. We were initially under the belief that the <code>terminationGracePeriodSeconds</code> value within our deployment would allow the pod to continue running for the defined number of seconds. However, we were mistaken. This value tells Kubernetes to allow the application running within the pod some time to clean up. It does <em>not</em> tell the app to continue running for the defined number of seconds after it receives a sigterm signal. This logic actually needs to be implemented within the application itself, or with a prestop hook. The prestop method is <a href="https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/">well documented</a>, so I will not cover it here.</p> -<p>To implement this in a .NET Framework app running in Windows, you need to add this registry key to your container.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">RUN</span> reg add hklm<span style="color:#ae81ff">\s</span>ystem<span style="color:#ae81ff">\c</span>urrentcontrolset<span style="color:#ae81ff">\c</span>ontrol /v WaitToKillServiceTimeout /t REG_SZ /d <span style="color:#ae81ff">60000</span> /f<span style="color:#960050;background-color:#1e0010"> -</span></span></span></code></pre></div><p>This value tells Windows to wait a number of milliseconds before shutting down Normally, Windows only waits for 5 seconds (default) before shutting down any &lsquo;background&rsquo; processes. Windows forcibly shuts down processes after this period of time.</p> -<p>Next, in the startup class, we&rsquo;ll add the following code. I have added inline comments to explain.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c#" data-lang="c#"><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">namespace</span> MyApp.APIConsoleHost -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Program</span> -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Register the SetConsoleCtrlHandler function in kernel32.dll in the -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> application to capture CTRL_SHUTDOWN_EVENT events for resource reclamation -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e"> [DllImport(&#34;Kernel32&#34;)]</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">extern</span> <span style="color:#66d9ef">bool</span> SetConsoleCtrlHandler(HandlerRoutine handler, <span style="color:#66d9ef">bool</span> <span style="color:#66d9ef">add</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Define a delegate for our handler routine</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">delegate</span> <span style="color:#66d9ef">bool</span> HandlerRoutine(CtrlTypes ctrlType); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">volatile</span> ManualResetEvent _exitEvent = <span style="color:#66d9ef">new</span> ManualResetEvent(<span style="color:#66d9ef">false</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> HandlerRoutine _handler; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Define the event types that we want to handle when the application receives a SIGTERM -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_C_EVENT = 0, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_BREAK_EVENT = 1, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_CLOSE_EVENT = 2, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_LOGOFF_EVENT = 5, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_SHUTDOWN_EVENT = 6 -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">enum</span> CtrlTypes -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> CTRL_SHUTDOWN_EVENT = <span style="color:#ae81ff">6</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Here we are defining how we want to handle the shutdown -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We get a timeout value from an env variable named APP_SHUTDOWN_TIMEOUT -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> If that env variable is not found, we default to 60 seconds. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We then switch on our CtrlTypes enum and handle each value accordingly, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then return true. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">bool</span> ConsoleCtrlCheck(CtrlTypes ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> timeout = ConfigurationManager.AppSettings[<span style="color:#e6db74">&#34;APP_SHUTDOWN_TIMEOUT&#34;</span>]; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> (<span style="color:#66d9ef">string</span>.IsNullOrEmpty(timeout)) { timeout = <span style="color:#e6db74">&#34;60&#34;</span>; } -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">int</span> counter = <span style="color:#66d9ef">int</span>.Parse(timeout); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">switch</span> (ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> CtrlTypes.CTRL_SHUTDOWN_EVENT: -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] CTRL_SHUTDOWN received&#34;</span>); -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] Web Server is stopping in {counter} seconds&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">while</span> (counter &gt; <span style="color:#ae81ff">0</span>) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> Thread.Sleep(TimeSpan.FromSeconds(<span style="color:#ae81ff">1</span>)); -</span></span><span style="display:flex;"><span> counter--; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.Set(); -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span>; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span>: -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">false</span>; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Our main method is pretty standard. However, we first register a new handler (_handler), -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then pass it to to the SetConsoleCtrlHandler() method we imported from Kernel32.dll. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> The only other &#39;unique&#39; thing is the _exitEvent.WaitOne(); call defined at the bottom of main(). -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> This is necessary so that main does not immediately exit, and wait&#39;s for a signal. We defined a -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> property for this _exitEvent of type ManualResetEvent at the top of this class file. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> Main(<span style="color:#66d9ef">string</span>[] args) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> _handler += <span style="color:#66d9ef">new</span> HandlerRoutine(ConsoleCtrlCheck); -</span></span><span style="display:flex;"><span> SetConsoleCtrlHandler(_handler, <span style="color:#66d9ef">true</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = BuildStartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> WebApp.Start&lt;SelfHostStartup&gt;(startOptions); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">&#34;Press CTRL+C to stop it&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.WaitOne(); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> StartOptions BuildStartOptions() -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = <span style="color:#66d9ef">new</span> StartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted start options</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> startOptions; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>To prevent the HandlerRoutine instance from being recycled by the GC before the program exits, the HandlerRoutine must be static (as seen in the above example). This is important because if the handlerroutine is recycled before the application is finished, it will throw an error, as shown here:</p> -<pre tabindex="0"><code>A callback was made on a garbage collected delegate of type &#39;Program+HandlerRoutine::Invoke&#39;. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called. -</code></pre> + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. - diff --git a/public/tags/software-development/page/1/index.html b/public/tags/software-development/page/1/index.html index 05ccba25..0fef456c 100644 --- a/public/tags/software-development/page/1/index.html +++ b/public/tags/software-development/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/software-development/ - + http://localhost:1313/tags/software-development/ + - + diff --git a/public/tags/software/index.html b/public/tags/software/index.html index f20835a1..7ae0ef42 100644 --- a/public/tags/software/index.html +++ b/public/tags/software/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Software · GeekyRyan + - - -Software - GeekyRyan + - + + + - - - + + + - + + + + + + - - - + + + + - - - - - - - - - - - - - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,579 +79,176 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - -
    -
    - -

    Tag: Software

    - - - -
    -
    -
    -

    Chaining YAML Pipelines in Azure Devops

    -
    - -
    - - -
    - In this article, we’ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to figure this out. -Our two pipelines will exist in the same repository. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Update Azure Devops SPN Secret

    -
    - -
    - - -
    - If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal. -In this article, I’ll show you two methods for updating a secret for a service principal prior to expiration. -Update the secret via the Azure Devops Portal: Go to “Service Connections” in the Azure Devops portal Find the SPN you want to update, then click “Manage Service Principal” Then on the service principal page, click Certificates & Secrets Create a “New Client Secret”, take note of the value Delete the ‘old’ secret Return to the Service Connection in the Azure Devops portal Click Edit - click the verify button. -
    - - -
    - Read more -
    - - - - - - - -
    - -
    -
    -
    -

    Use “replace” in go.mod to Point to a Local Module

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Tag: Software +

    +
    + + + - https://rnemeth90.github.io/posts/2022-09-06-go-mod-replace-copy/ - Ryan - - -
    - - - - - - -
    -
    - -
    - -
    -
    -
    -

    Powershell for Devops - Querying REST APIs with Powershell

    -
    - -
    - -
    - This will be a short post on querying REST APIs with Powershell. -It’s hard to argue that REST APIs are the predominant technology for interacting with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) product without having to go through the exercise of a more complicated integration. REST APIs communicate in a common format, typically JSON. However, most will allow us to choose the response format by specifying an option in the ‘Accept’ header. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Reading Json Files with Go

    -
    - -
    - - -
    - JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting with it, and most public APIs accept JSON in HTTP requests. -In this post, we’ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the JSON data within the file into a memory structure. -
    +
    +
    + © + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - +
    +
    -
    - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/software/index.xml b/public/tags/software/index.xml index 3d7945ce..27d7607c 100644 --- a/public/tags/software/index.xml +++ b/public/tags/software/index.xml @@ -2,305 +2,46 @@ Software on GeekyRyan - https://rnemeth90.github.io/tags/software/ - GeekyRyan (Software) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/software/ + Recent content in Software on GeekyRyan + Hugo + en Thu, 03 Nov 2022 00:00:00 +0000 - - - - + Chaining YAML Pipelines in Azure Devops - https://rnemeth90.github.io/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ + http://localhost:1313/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ Thu, 03 Nov 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ - <p>In this article, we&rsquo;ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. -Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to -figure this out.</p> -<p>Our two pipelines will exist in the same repository. We have a dependent-pipeline, that we only want to run once the source-pipeline is finished. This is useful if you have -some infrastructure you want to build, prior to deploying something to that infrastructure.</p> -<p>The process is actually quite simple. First, let&rsquo;s define our source pipeline:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># source-pipeline</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: <span style="color:#ae81ff">echo Hello, world!</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a one-line script&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo Add other tasks to build, test, and deploy your project. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo See https://aka.ms/yaml</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a multi-line script&#39;</span> -</span></span></code></pre></div><p>Nothing fancy here, just the build in template pipeline that Microsoft gives us for free when we create a &ldquo;Starter Pipeline&rdquo;.</p> -<p>Now, let&rsquo;s create another pipeline in the same repo that will be triggered when the pipeline above completes:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># dependent-pipeline</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">trigger</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#ae81ff">none</span> <span style="color:#75715e"># we want this pipeline to be triggered manually, not based on PR, etc.</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">pool</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">vmImage</span>: <span style="color:#ae81ff">ubuntu-latest</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">pipelines</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">pipeline</span>: <span style="color:#ae81ff">source-pipeline</span> <span style="color:#75715e">#this can be anything</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">source</span>: <span style="color:#e6db74">&#39;source-pipeline&#39;</span> <span style="color:#75715e">#this needs to be the name of the &#39;source&#39; pipeline</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">trigger</span>: <span style="color:#66d9ef">true</span> <span style="color:#75715e"># Run dependent-pipeline pipeline when any run of security-lib-ci completes</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">steps</span>: -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: <span style="color:#ae81ff">echo Hello, world!</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a one-line script&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>- <span style="color:#f92672">script</span>: |<span style="color:#e6db74"> -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo Add other tasks to build, test, and deploy your project. -</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> echo See https://aka.ms/yaml</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">displayName</span>: <span style="color:#e6db74">&#39;Run a multi-line script&#39;</span> -</span></span></code></pre></div><p>The resources block above defines our dependency. You want to be sure to configure the trigger of the dependent pipeline appropriately as well.</p> -<p>There are several options for fine-tuning this process. See the office Microsoft documentation below:</p> -<p><a href="https://learn.microsoft.com/en-us/azure/devops/pipelines/process/pipeline-triggers?view=azure-devops">Link to the Microsoft Docs</a></p> - + http://localhost:1313/posts/2022-11-03-chaining-yaml-pipelines-in-azure-devops-copy/ + In this article, we&rsquo;ll take a quick look at chaining two pipelines together in Azure Devops, so that the completion of one pipeline, triggers the other to run. Microsoft documentation is leaps and bounds ahead of where it used to be. However, I still feel like there is a lot of room for improvement, as it took me a while to figure this out. Our two pipelines will exist in the same repository. - Update Azure Devops SPN Secret - https://rnemeth90.github.io/posts/2022-09-12-update-azure-devops-spn-secret/ + http://localhost:1313/posts/2022-09-12-update-azure-devops-spn-secret/ Mon, 12 Sep 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-09-12-update-azure-devops-spn-secret/ - <p>If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal.</p> -<p>In this article, I&rsquo;ll show you two methods for updating a secret for a service principal prior to expiration.</p> -<h1 id="update-the-secret-via-the-azure-devops-portal" >Update the secret via the Azure Devops Portal: -<span> - <a href="#update-the-secret-via-the-azure-devops-portal"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h1><ul> -<li>Go to &ldquo;Service Connections&rdquo; in the Azure Devops portal</li> -<li>Find the SPN you want to update, then click &ldquo;Manage Service Principal&rdquo;</li> -<li>Then on the service principal page, click Certificates &amp; Secrets</li> -<li>Create a &ldquo;New Client Secret&rdquo;, take note of the value</li> -<li>Delete the &lsquo;old&rsquo; secret</li> -<li>Return to the Service Connection in the Azure Devops portal</li> -<li>Click Edit - click the verify button. It should tell you the client certificate has expired</li> -<li>Now you need to make an arbitrary change and save it. I just type a character in the optional description and save.</li> -<li>Now edit again and click verify, it will now pick up the new client secret and all is happy.</li> -<li>You can now remove whatever you added to the description.</li> -</ul> - + http://localhost:1313/posts/2022-09-12-update-azure-devops-spn-secret/ + If you need to update the secret for a service principal in Azure Devops, prior to it expiring, you may be surprised to find that this cannot be done via the Azure Portal. In this article, I&rsquo;ll show you two methods for updating a secret for a service principal prior to expiration. Update the secret via the Azure Devops Portal: Link to heading Go to &ldquo;Service Connections&rdquo; in the Azure Devops portal Find the SPN you want to update, then click &ldquo;Manage Service Principal&rdquo; Then on the service principal page, click Certificates &amp; Secrets Create a &ldquo;New Client Secret&rdquo;, take note of the value Delete the &lsquo;old&rsquo; secret Return to the Service Connection in the Azure Devops portal Click Edit - click the verify button. - Use “replace” in go.mod to Point to a Local Module - https://rnemeth90.github.io/posts/2022-09-06-go-mod-replace-copy/ + http://localhost:1313/posts/2022-09-06-go-mod-replace-copy/ Tue, 06 Sep 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-09-06-go-mod-replace-copy/ - <p>If you want to the local version of a dependency in Go rather than one in a remote repository, use the <em>replace</em> keyword.</p> -<p>The replace line goes above your require statements, like so:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> module github.com/rnemeth90/foo -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> replace github.com/rnemeth90/bar <span style="color:#f92672">=</span>&gt; /Users/rnemeth90/Projects/bar -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> require <span style="color:#f92672">(</span> -</span></span><span style="display:flex;"><span> github.com/rnemeth90/bar v1.0.0 -</span></span><span style="display:flex;"><span> <span style="color:#f92672">)</span> -</span></span></code></pre></div><p>Now when you compile this module <em>go build</em> or <em>go install</em>, it will use your local code rather than the remote dependency.</p> -<p>According to the docs, you do need to make sure that the code you’re pointing to also has a <strong>go.mod</strong> file:</p> -<blockquote> -<p><strong>Note</strong>: if the right-hand side of a <code>replace</code> directive is a filesystem path, then the target must have a <code>go.mod</code> file at that location. If the <code>go.mod</code> file is not present, you can create one with <code>go mod init</code>.</p> -<p><a href="https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive">https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive</a></p> -</blockquote> -<p>You can also create this line from the command line using the <strong>go mod edit</strong> command.</p> -<pre><code>$ go mod edit -replace github.com/rnemeth90/bar=/Users/rnemeth90/Projects/bar -</code></pre> -<p>Following the <strong>-replace</strong> is first what you want to replace, then an equals sign, then what you’re replacing it with.</p> -<p>Hopefully this helps someone who was stuck with this like me 🙂</p> - + http://localhost:1313/posts/2022-09-06-go-mod-replace-copy/ + If you want to the local version of a dependency in Go rather than one in a remote repository, use the replace keyword. The replace line goes above your require statements, like so: module github.com/rnemeth90/foo replace github.com/rnemeth90/bar =&gt; /Users/rnemeth90/Projects/bar require ( github.com/rnemeth90/bar v1.0.0 ) Now when you compile this module go build or go install, it will use your local code rather than the remote dependency. According to the docs, you do need to make sure that the code you’re pointing to also has a go. - Powershell for Devops - Querying REST APIs with Powershell - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ Thu, 04 Aug 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-08-04-querying-rest-with-powershell/ - <p>This will be a short post on querying REST APIs with Powershell.</p> -<p>It&rsquo;s hard to argue that REST APIs are the predominant technology for interacting -with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) -product without having to go through the exercise of a more complicated integration. REST APIs communicate -in a common format, typically JSON. However, most will allow us to choose the response format by specifying an -option in the &lsquo;Accept&rsquo; header. Most languages provide a native method for interacting with -REST APIs. This objective for this post is to show you how simple this is with Powershell.</p> -<p>To get started, we&rsquo;ll need a public API to interact with. I&rsquo;m going to use <a href="https://icanhazdadjoke.com/">https://icanhazdadjoke.com/</a>, because -there is no authentication and no rate-limiting (two concepts we will cover in another post).</p> -<p>Calling the API is extremely simple:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -</span></span></code></pre></div><p>However, this results in the content being returned as plain text. This isn&rsquo;t ideal.</p> -<p>Let&rsquo;s pass the &lsquo;Accept&rsquo; header to tell the API the format we are expecting to be returned:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers -</span></span></code></pre></div><p>Output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>[<span style="color:#ae81ff">15</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">04</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">34</span>] C:\..\..\rnemeth90.github.io on <span style="color:#960050;background-color:#1e0010"></span>main <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#ae81ff">+1</span> <span style="color:#960050;background-color:#1e0010">❯</span> Invoke-RestMethod -Uri $url -Method Get -Headers $headers -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>id joke status -</span></span><span style="display:flex;"><span>-- ---- ------ -</span></span><span style="display:flex;"><span>3LmyXvsPfqc I don<span style="color:#e6db74">&#39;t trust stairs. They&#39;</span>re always up to something. <span style="color:#ae81ff">200</span> -</span></span></code></pre></div><p>That looks a little better. For those of you familiar with Powershell, the output above probably -looks completely normal. But for those not-so-familiar with Powershell, or those expecting -more of a &lsquo;json-esk&rsquo; output, this may look a bit&hellip; weird.</p> -<p>Powershell is an object oriented language. <strong>Everything is an object</strong> in Powershell, even the response -of this request. What you see in the output is simply the properties of the object.</p> -<p>Luckily Powershell provides us with a cmdlet to convert an object into json (aptly named: ConvertTo-Json). We can use it like this:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers | ConvertTo-Json -</span></span></code></pre></div><p>Here we are piping the output from Invoke-RestMethod to ConvertTo-Json. Pretty neat!</p> -<p>Output:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>[<span style="color:#ae81ff">15</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">04</span><span style="color:#960050;background-color:#1e0010">:</span><span style="color:#ae81ff">35</span>] C:\..\..\rnemeth90.github.io on <span style="color:#960050;background-color:#1e0010"></span>main <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#960050;background-color:#1e0010"></span> <span style="color:#ae81ff">+1</span> <span style="color:#960050;background-color:#1e0010">❯</span> Invoke-RestMethod -Uri $url -Method Get -Headers $headers | Convertto-json -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;id&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#e6db74">&#34;AAdFBXnGlyd&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;joke&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#e6db74">&#34;If you walk into a forest and cut down a tree, but the tree doesn&#39;t understand why you cut it down, do you think it&#39;s stumped?&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;status&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#ae81ff">200</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Now, that looks more normal.</p> -<p>There is much more we can do with Invoke-RestMethod. The &lsquo;Method&rsquo; parameter of this cmdlet accepts any of the common -HTTP methods (GET, PUT, PATCH, DELETE, POST, HEAD). You can also specify other headers and a body (using the -body parameter).</p> -<p>Both of these parameters accept dictionaries:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://icanhazdadjoke.com/&#34;</span> -</span></span><span style="display:flex;"><span>$headers = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Accept&#39;</span> = <span style="color:#e6db74">&#39;application/json&#39;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Host&#39;</span> = <span style="color:#e6db74">&#39;MyServer&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>$body = @{ -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#39;Eat&#39;</span> = <span style="color:#e6db74">&#39;Pizza&#39;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span>Invoke-RestMethod -Uri $url -Method Get -Headers $headers -Body $body | ConvertTo-Json -</span></span></code></pre></div><p>Unfortunately I won&rsquo;t be able to show the other HTTP methods, as this API only supports GET requests. So that&rsquo;s all for now.</p> - + http://localhost:1313/posts/2022-08-04-querying-rest-with-powershell/ + This will be a short post on querying REST APIs with Powershell. It&rsquo;s hard to argue that REST APIs are the predominant technology for interacting with networked services. They provide a gateway for interacting with a 3rd party (or self-hosted) product without having to go through the exercise of a more complicated integration. REST APIs communicate in a common format, typically JSON. However, most will allow us to choose the response format by specifying an option in the &lsquo;Accept&rsquo; header. - Reading Json Files with Go - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ + http://localhost:1313/posts/2022-07-21-reading-json-files-with-go/ Thu, 21 Jul 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-07-21-reading-json-files-with-go/ - <p>JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting -with it, and most public APIs accept JSON in HTTP requests.</p> -<p>In this post, we&rsquo;ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the -JSON data within the file into a memory structure.</p> -<p>Let&rsquo;s assume we have the following JSON data representing an employee:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">1</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Steve&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Rogers&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Captain America&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Department&#34;</span>: <span style="color:#e6db74">&#34;Avengers&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>We need a way of representing this data in memory when decoding it from JSON. For this, we will need to create a struct:</p> -<p>We will build up our go module as we progress through the article</p> -<p>Let&rsquo;s start:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#75715e">// main.go -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> ( -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;encoding/json&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;fmt&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;io/ioutil&#34;</span> -</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;log&#34;</span> -</span></span><span style="display:flex;"><span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#75715e">// Hero represents an hero -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// ALL fields must be exportable! Otherwise the JSON parsing will fail. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Hero</span> <span style="color:#66d9ef">struct</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Id</span> <span style="color:#66d9ef">int</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">FirstName</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">LastName</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Alias</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">Group</span> <span style="color:#66d9ef">string</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() { -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Here we set the log prefix. When reading stack traces, this makes it easier to know -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// where a failure occurred. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">SetPrefix</span>(<span style="color:#e6db74">&#34;main(): &#34;</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// We first need to load the JSON file into memory -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">content</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">ioutil</span>.<span style="color:#a6e22e">ReadFile</span>(<span style="color:#e6db74">&#34;./heros.json&#34;</span>) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#e6db74">&#34;Error opening the file: &#34;</span>, <span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Now we parse the JSON data into a memory structure. We know our JSON file will have more than one hero object, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// so we&#39;ll use make() to create a []Hero slice. Since go is a pass-by-value language, we will then use the address-of -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// operator (&amp;) to unmarshal our json data into the heros slice -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">heros</span> <span style="color:#f92672">:=</span> make([]<span style="color:#a6e22e">Hero</span>, <span style="color:#ae81ff">5</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">json</span>.<span style="color:#a6e22e">Unmarshal</span>(<span style="color:#a6e22e">content</span>, <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">heros</span>) -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#e6db74">&#34;Error occurred during unmarshal: &#34;</span>, <span style="color:#a6e22e">err</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// now we can read/interact with the data. We&#39;ll loop over the array -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#75715e">// and print the values in memory -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> &lt; len(<span style="color:#a6e22e">heros</span>); <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span> { -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">Id</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">FirstName</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">LastName</span>) -</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">heros</span>[<span style="color:#a6e22e">i</span>].<span style="color:#a6e22e">Group</span>) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Create a file named employees.json with similar data:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>[ -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">1</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Steve&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Rogers&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Captain America&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;group&#34;</span>: <span style="color:#e6db74">&#34;Avengers&#34;</span> -</span></span><span style="display:flex;"><span> }, -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Id&#34;</span>: <span style="color:#ae81ff">2</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;firstName&#34;</span>: <span style="color:#e6db74">&#34;Clark&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;lastName&#34;</span>: <span style="color:#e6db74">&#34;Kent&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;alias&#34;</span>: <span style="color:#e6db74">&#34;Superman&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;group&#34;</span>: <span style="color:#e6db74">&#34;Justice League&#34;</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>] -</span></span></code></pre></div><p>Now, we can run our main.go file:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>11:40:47 ryan@xerxes json → go run main.go -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span> -</span></span><span style="display:flex;"><span>Steve -</span></span><span style="display:flex;"><span>Rogers -</span></span><span style="display:flex;"><span>Avengers -</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span>Clark -</span></span><span style="display:flex;"><span>Kent -</span></span><span style="display:flex;"><span>Justice League -</span></span><span style="display:flex;"><span>11:40:49 ryan@xerxes json -</span></span></code></pre></div><p>Pretty simple! That&rsquo;s why I love go. We accomplished all of this with ~50 lines of code. -Doing something similar in asp.net project would easily double that count and involve creating -multiple files! (nothing against asp.net or c#, I think c# is a great language and use it daily)</p> -<p>Now, &lsquo;go&rsquo; try this!</p> - + http://localhost:1313/posts/2022-07-21-reading-json-files-with-go/ + JSON is a widely used format for representing structured data. Developers like it because it is easy to read, most common languages have a library for interacting with it, and most public APIs accept JSON in HTTP requests. In this post, we&rsquo;ll look at parsing a JSON file using Go! We will be using the io/ioutil package to open a json file on local disk, and encoding/json to parse the JSON data within the file into a memory structure. - diff --git a/public/tags/software/page/1/index.html b/public/tags/software/page/1/index.html index a9da9c58..1a192780 100644 --- a/public/tags/software/page/1/index.html +++ b/public/tags/software/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/software/ - + http://localhost:1313/tags/software/ + - + diff --git a/public/tags/sre/index.html b/public/tags/sre/index.html index 8ff15fa8..76d72016 100644 --- a/public/tags/sre/index.html +++ b/public/tags/sre/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: SRE · GeekyRyan + - - -SRE - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,303 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Tag: SRE

    - - - -
    -
    -
    -

    Handling Graceful Shutdown in a .NET App Hosted in Kubernetes

    -
    -
    +
    +
    + © -
    - I was recently involved with troubleshooting some API’s hosted in Kubernetes throwing http/502’s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/sre/index.xml b/public/tags/sre/index.xml index 7726f850..9045d5b4 100644 --- a/public/tags/sre/index.xml +++ b/public/tags/sre/index.xml @@ -2,137 +2,18 @@ SRE on GeekyRyan - https://rnemeth90.github.io/tags/sre/ - GeekyRyan (SRE) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/sre/ + Recent content in SRE on GeekyRyan + Hugo + en Wed, 28 Dec 2022 00:00:00 +0000 - - - - + Handling Graceful Shutdown in a .NET App Hosted in Kubernetes - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ Wed, 28 Dec 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ - <p>I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. It was actually a combination of these blogs (and the resolutions posted) that ended up resolving our issue.</p> -<h3 id="so-what-was-actually-causing-the-502s" >So what was actually causing the 502&rsquo;s? -<span> - <a href="#so-what-was-actually-causing-the-502s"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h3><p>As stated, these APIs are hosted in Kubernetes. They are written primarily in c# (.NET Framework) and hosted in Windows Server Core containers. The pods are load balanced using a service, and we have an Nginx ingress on top of the service. Nothing fancy, just a typical setup that you may have seen or even built yourself. We implement automatic scaling for our replica sets using a standard Kubernetes-native HPA or Keda, depending on the app. We have autoscale rules defined for the pods. Our clusters are hosted in Azure Kubernetes Service, and we autoscale our node pools. So, there are several layers of scaling happening in our clusters at any given time. Occasionally, when a pod was handling a client request, Kubelet or a controller would come along and scale the pod in. We were initially under the belief that the <code>terminationGracePeriodSeconds</code> value within our deployment would allow the pod to continue running for the defined number of seconds. However, we were mistaken. This value tells Kubernetes to allow the application running within the pod some time to clean up. It does <em>not</em> tell the app to continue running for the defined number of seconds after it receives a sigterm signal. This logic actually needs to be implemented within the application itself, or with a prestop hook. The prestop method is <a href="https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/">well documented</a>, so I will not cover it here.</p> -<p>To implement this in a .NET Framework app running in Windows, you need to add this registry key to your container.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">RUN</span> reg add hklm<span style="color:#ae81ff">\s</span>ystem<span style="color:#ae81ff">\c</span>urrentcontrolset<span style="color:#ae81ff">\c</span>ontrol /v WaitToKillServiceTimeout /t REG_SZ /d <span style="color:#ae81ff">60000</span> /f<span style="color:#960050;background-color:#1e0010"> -</span></span></span></code></pre></div><p>This value tells Windows to wait a number of milliseconds before shutting down Normally, Windows only waits for 5 seconds (default) before shutting down any &lsquo;background&rsquo; processes. Windows forcibly shuts down processes after this period of time.</p> -<p>Next, in the startup class, we&rsquo;ll add the following code. I have added inline comments to explain.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c#" data-lang="c#"><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">namespace</span> MyApp.APIConsoleHost -</span></span><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Program</span> -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Register the SetConsoleCtrlHandler function in kernel32.dll in the -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> application to capture CTRL_SHUTDOWN_EVENT events for resource reclamation -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span><span style="color:#a6e22e"> [DllImport(&#34;Kernel32&#34;)]</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">extern</span> <span style="color:#66d9ef">bool</span> SetConsoleCtrlHandler(HandlerRoutine handler, <span style="color:#66d9ef">bool</span> <span style="color:#66d9ef">add</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// Define a delegate for our handler routine</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">delegate</span> <span style="color:#66d9ef">bool</span> HandlerRoutine(CtrlTypes ctrlType); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">volatile</span> ManualResetEvent _exitEvent = <span style="color:#66d9ef">new</span> ManualResetEvent(<span style="color:#66d9ef">false</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> HandlerRoutine _handler; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Define the event types that we want to handle when the application receives a SIGTERM -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_C_EVENT = 0, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_BREAK_EVENT = 1, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_CLOSE_EVENT = 2, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_LOGOFF_EVENT = 5, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> CTRL_SHUTDOWN_EVENT = 6 -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">enum</span> CtrlTypes -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> CTRL_SHUTDOWN_EVENT = <span style="color:#ae81ff">6</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Here we are defining how we want to handle the shutdown -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We get a timeout value from an env variable named APP_SHUTDOWN_TIMEOUT -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> If that env variable is not found, we default to 60 seconds. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> We then switch on our CtrlTypes enum and handle each value accordingly, -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then return true. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">bool</span> ConsoleCtrlCheck(CtrlTypes ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> timeout = ConfigurationManager.AppSettings[<span style="color:#e6db74">&#34;APP_SHUTDOWN_TIMEOUT&#34;</span>]; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> (<span style="color:#66d9ef">string</span>.IsNullOrEmpty(timeout)) { timeout = <span style="color:#e6db74">&#34;60&#34;</span>; } -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">int</span> counter = <span style="color:#66d9ef">int</span>.Parse(timeout); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">switch</span> (ctrlType) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">case</span> CtrlTypes.CTRL_SHUTDOWN_EVENT: -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] CTRL_SHUTDOWN received&#34;</span>); -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">$&#34;[{DateTime.UtcNow}] Web Server is stopping in {counter} seconds&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">while</span> (counter &gt; <span style="color:#ae81ff">0</span>) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> Thread.Sleep(TimeSpan.FromSeconds(<span style="color:#ae81ff">1</span>)); -</span></span><span style="display:flex;"><span> counter--; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.Set(); -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span>; -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span>: -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">false</span>; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">/* -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Our main method is pretty standard. However, we first register a new handler (_handler), -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> and then pass it to to the SetConsoleCtrlHandler() method we imported from Kernel32.dll. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> The only other &#39;unique&#39; thing is the _exitEvent.WaitOne(); call defined at the bottom of main(). -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> This is necessary so that main does not immediately exit, and wait&#39;s for a signal. We defined a -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> property for this _exitEvent of type ManualResetEvent at the top of this class file. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> Main(<span style="color:#66d9ef">string</span>[] args) -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> _handler += <span style="color:#66d9ef">new</span> HandlerRoutine(ConsoleCtrlCheck); -</span></span><span style="display:flex;"><span> SetConsoleCtrlHandler(_handler, <span style="color:#66d9ef">true</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = BuildStartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted ....</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> WebApp.Start&lt;SelfHostStartup&gt;(startOptions); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> Console.WriteLine(<span style="color:#e6db74">&#34;Press CTRL+C to stop it&#34;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> _exitEvent.WaitOne(); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> StartOptions BuildStartOptions() -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">var</span> startOptions = <span style="color:#66d9ef">new</span> StartOptions(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#75715e">// redacted start options</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> startOptions; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>To prevent the HandlerRoutine instance from being recycled by the GC before the program exits, the HandlerRoutine must be static (as seen in the above example). This is important because if the handlerroutine is recycled before the application is finished, it will throw an error, as shown here:</p> -<pre tabindex="0"><code>A callback was made on a garbage collected delegate of type &#39;Program+HandlerRoutine::Invoke&#39;. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called. -</code></pre> + http://localhost:1313/posts/2022-12-28-graceful-shutdown-in-kubernetes-dotnet-pod/ + I was recently involved with troubleshooting some API&rsquo;s hosted in Kubernetes throwing http/502&rsquo;s. This was incredibly difficult to diagnose because it seemingly happened at random, and I had never encountered anything like this. Being that I had never dealt with this in the past, and I (nor my team) was able to figure it out within a reasonable amount of time, I turned to google. My searches resulted in various blogs and SO posts of other people experiencing similar issues, but none of their resolutions worked for us. - diff --git a/public/tags/sre/page/1/index.html b/public/tags/sre/page/1/index.html index 1f8efd20..90d85422 100644 --- a/public/tags/sre/page/1/index.html +++ b/public/tags/sre/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/sre/ - + http://localhost:1313/tags/sre/ + - + diff --git a/public/tags/storage/index.html b/public/tags/storage/index.html index 7ddad122..5b3650ba 100644 --- a/public/tags/storage/index.html +++ b/public/tags/storage/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Storage · GeekyRyan + - - -storage - GeekyRyan - - - - - - - - - - + - - + + + - - + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,363 +79,161 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    -
    -
    - -

    Tag: storage

    - + 2022-07-19 + AKS Scale Down Mode + +
  • + 2022-03-01 + Kubernetes Storage Simplified +
  • -
    -
    -
    -

    AKS Scale Down Mode

    -
    - -
    + + - -
    - By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete or deallocate nodes. -Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Kubernetes Storage Simplified

    -
    -
    +
    +
    + © -
    - In this blog post, we will attempt to explain the current storage options that exist in Kubernetes. If you are new to Kubernetes, learning about its capabilities of managing the application state can be a daunting task. -Container images are built-in layers, with the runtime layer being writable. However, any files on this writable layer are only available for the container’s lifetime. We can mount a volume to a directory inside the container to have persistent data. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - +
    +
    -
    - https://rnemeth90.github.io/posts/2022-03-01-kubernetes-storage-simplified/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/storage/index.xml b/public/tags/storage/index.xml index d2a6e39e..be4382fc 100644 --- a/public/tags/storage/index.xml +++ b/public/tags/storage/index.xml @@ -1,248 +1,26 @@ - storage on GeekyRyan - https://rnemeth90.github.io/tags/storage/ - GeekyRyan (storage) - Hugo -- gohugo.io - en-us + Storage on GeekyRyan + http://localhost:1313/tags/storage/ + Recent content in Storage on GeekyRyan + Hugo + en Tue, 19 Jul 2022 00:00:00 +0000 - - - - + AKS Scale Down Mode - https://rnemeth90.github.io/posts/2022-07-19-aks-scale-down-mode/ + http://localhost:1313/posts/2022-07-19-aks-scale-down-mode/ Tue, 19 Jul 2022 00:00:00 +0000 - - https://rnemeth90.github.io/posts/2022-07-19-aks-scale-down-mode/ - <p>By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete <em>or</em> deallocate nodes.</p> -<p>Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. However, you will still need to pay for any storage that the node is using. Having persistent storage also means that any container images that were cached on the node will still be there when the node starts back up. This can be a major performance benefit if you are using Windows containers because the images for these containers are typically very large.</p> -<p>Scale down mode can be configured in several ways. Here, we will look at configuring it via the Azure CLI and Terraform.</p> -<p>Azure CLI:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>az aks nodepool update --scale-down-mode Deallocate --name nplinux01 --cluster-name myAKSCluster --resource-group myResourceGroup -</span></span></code></pre></div><p>Terraform:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-hcl" data-lang="hcl"><span style="display:flex;"><span><span style="color:#66d9ef">resource</span> <span style="color:#e6db74">&#34;azurerm_kubernetes_cluster_node_pool&#34; &#34;nodepool&#34;</span> { -</span></span><span style="display:flex;"><span> name <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;nplinux01&#34;</span> -</span></span><span style="display:flex;"><span> kubernetes_cluster_id <span style="color:#f92672">=</span> <span style="color:#66d9ef">azurerm_kubernetes_cluster</span>.<span style="color:#66d9ef">example</span>.<span style="color:#66d9ef">id</span> -</span></span><span style="display:flex;"><span> vm_size <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Standard_DS2_v2&#34;</span> -</span></span><span style="display:flex;"><span> node_count <span style="color:#f92672">=</span> <span style="color:#ae81ff">2</span> -</span></span><span style="display:flex;"><span> scale_down_mode <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Deallocate&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> tags <span style="color:#f92672">=</span> { -</span></span><span style="display:flex;"><span> Environment <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;lab&#34;</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><em>At the time of this writing, Terraform does not support configuring scale-down mode for the default AKS node pool.</em> -<em>Node pools using ephemeral disks do not support &lsquo;deallocate&rsquo; mode</em></p> - + http://localhost:1313/posts/2022-07-19-aks-scale-down-mode/ + By default, scale-out operations performed manually or by cluster autoscale rules require the allocation and provisioning of new nodes, and scale-in operations delete nodes. Scale-down mode is a relatively newer concept that allows us to choose whether to delete or deallocate nodes. Having the ability to deallocate, rather than delete, nodes is a major performance benefit, as the time it takes to spin up new nodes will be significantly decreased. You will not be charged when nodes are deallocated. - Kubernetes Storage Simplified - https://rnemeth90.github.io/posts/2022-03-01-kubernetes-storage-simplified/ + http://localhost:1313/posts/2022-03-01-kubernetes-storage-simplified/ Tue, 01 Mar 2022 08:37:58 +0000 - - https://rnemeth90.github.io/posts/2022-03-01-kubernetes-storage-simplified/ - <p>In this blog post, we will attempt to explain the current storage options that exist in Kubernetes. If you are new to Kubernetes, learning about its capabilities of managing the application state can be a daunting task.</p> -<p>Container images are built-in layers, with the runtime layer being writable. However, any files on this writable layer are only available for the container’s lifetime. We can mount a volume to a directory inside the container to have persistent data.</p> -<p>Kubernetes storage uses the concepts of volumes. Ephemeral volumes are called volumes and only last the lifetime of a pod, and “persistent volumes” are used for long-term storage. A typical use case for Ephemeral volumes is storing logs that are not sent to stdout.</p> -<p>Mounting a persistent volume inside a container allows you to persist the state of your application long after the container is terminated. Persistent volumes can also take advantage of the typical storage idiosyncrasies such as backup, compression, and encryption.</p> -<h2 id="persistent-volumes" >Persistent Volumes -<span> - <a href="#persistent-volumes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Kubernetes has several types of persistent volumes. At its core, a persistent volume is simply a directory mounted inside a pod. How that volume is created, the configuration options and the medium that backs it are all determined by the type of volume created.</p> -<p>There are several types of volumes available, too many to list here. You may commonly see some volume types: NFS, iSCSI, hostpath, and local. If your Kubernetes cluster exists in a cloud environment such as Azure or AWS, other volume types are available to you (azureDisk, azureFile, and awsElasticBlockStore, respectively). A complete list of types can be found here:</p> -<p><a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes">https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes</a></p> -<p>Creating a persistent volume is generally a simple task. The first step is determining the type of volume to create. In this post, we will cover creating a local volume. A local volume represents a disk, partition, or directory shared from a node. Local volumes are subject to the availability of the underlying node, meaning that if the node is offline, the volume is also offline and will not be accessible by any pod. Because of this, local volumes should not be used in production.</p> -<p>A persistent volume can only be created using a declarative approach. To create a persistent local volume, use the following YAML definition:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolume</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">example-pv</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">capacity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMode</span>: <span style="color:#ae81ff">Filesystem</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteOnce</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeReclaimPolicy</span>: <span style="color:#ae81ff">Delete</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">local-storage</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">local</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># the path to the volume or directory on the node</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/mnt/disks/ssd1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeAffinity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">required</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeSelectorTerms</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">matchExpressions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">key</span>: <span style="color:#ae81ff">kubernetes.io/hostname</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">operator</span>: <span style="color:#ae81ff">In</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">values</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># name of the node sharing the volume</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">node01</span> -</span></span></code></pre></div><p>When creating a persistent volume of this type, you must specify a node affinity. This ensures that the Kubernetes scheduler schedules any pods requesting access to this volume on the correct node. For example, any pod requesting access to the persistent volume named ‘example-PV will only be scheduled on the node ‘node01’.</p> -<p>Let’s dive into this persistent volume spec a bit more:</p> -<p>You can change the capacity of the persistent volume by updating:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">capacity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">100Gi</span> -</span></span></code></pre></div><p>The accessModes will be determined by the storage provider being used. There are generally 3 access modes available: ReadWriteOnce, ReadWriteMany, and ReadOnlyMany.</p> -<ul> -<li>ReadWriteOnce – The volume can be mounted as read-write by a single node</li> -<li>ReadWriteMany – The volume can be mounted as read-write by many nodes</li> -<li>ReadOnlyMany – The volume can be mounted as read-only by many nodes</li> -</ul> -<p>The “persistentVolumeReclaim” policy determines what happens to a persistent volume when it is no longer mounted by any pods (i.e., there are no claims to it, more on this later). There are three options available for the reclaim policy:</p> -<ul> -<li>Retain – The persistent volume is kept as-is. It must be manually removed when no longer needed.</li> -<li>Recycle – The persistent volume is scrubbed and can be re-used by other pods</li> -<li>Delete – The persistent volume is deleted.</li> -</ul> -<p>Currently, only NFS and hostPath volumes support recycling. Cloud storage providers (Azure, AWS, and GCE) support deletion.</p> -<p>The other aspects of this spec are unique to the volume being used. Since we are using a local volume here, we must specify the path to the directory or volume on the host and the host which is sharing the directory or volume:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span> <span style="color:#f92672">local</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># the path to the volume or directory on the node</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/mnt/disks/ssd1</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeAffinity</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">required</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">nodeSelectorTerms</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">matchExpressions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">key</span>: <span style="color:#ae81ff">kubernetes.io/hostname</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">operator</span>: <span style="color:#ae81ff">In</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">values</span>: -</span></span><span style="display:flex;"><span> <span style="color:#75715e"># name of the node sharing the volume</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">node01</span> -</span></span></code></pre></div><h2 id="ephemeral-volumes" >Ephemeral Volumes -<span> - <a href="#ephemeral-volumes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>Note: The Kubernetes documentation recognizes configMaps and Secrets as ephemeral volumes. However, in this article, we will only discuss ephemeral volumes used for data storage (emptyDir volumes).</p> -<p>Ephemeral volumes are defined within the context of a pod. This means that you cannot create an ephemeral volume on its own. Instead, define the ephemeral volume in the pod or a deployment spec.</p> -<p>Ephemeral volumes are useful in a few scenarios:</p> -<ol> -<li>You want to share data between multiple containers in a pod</li> -<li>You want to cache temporary information such as log files</li> -<li>You need scratch space to store data before it is processed by another container or pod</li> -</ol> -<p>If one of the containers in the pod happens to restart, data on the ephemeral volume will still exist; as long as one of the containers is mounting, it stays online. In other words, if a pod mounting the ephemeral volume is removed from a node, data on the ephemeral volume is lost. However, if a pod crashes, the data on the volume remains intact.</p> -<p>As stated previously, creating an ephemeral volume is done as part of the pod or deployment template:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/cache</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">emptyDir</span>: {} -</span></span></code></pre></div><p>If the template, you add a volume of type ’emptyDir’ in the ‘volumes’ spec and name it. You can mount this volume in any container in the pod. The volume does not have to be mounted to the same directory in each container.</p> -<h2 id="persistent-volume-claims" >Persistent Volume Claims -<span> - <a href="#persistent-volume-claims"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>A persistentVolumeClaim (often referred to as a ‘PVC’) is used by a pod to create a ‘claim’ on storage. Using a PVC, a pod can mount multiple persistent volumes simultaneously to any directory in the pod.</p> -<p>PersistentVolumeClaim’s are a Kubernetes primitive that can be deployed from a manifest:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">fast-storage-pvc</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMode</span>: <span style="color:#ae81ff">Filesystem</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">8Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">fast</span> -</span></span></code></pre></div><p>Most of the options in the manifest above seem pretty obvious. The volumeMode specifies whether to consume the persistent volume as a FileSystem or block device. The resources section helps specify the amount of storage you require (8Gi in this example). We will cover the storageClassName in the next section. Finally, the accessModes are identical to those described above in the Persistent Volumes section.</p> -<p>Pods access a volume by using the persistentVolumeClaim as volume. Claims must exist in the same namespace as the pod using the claim. The controller finds the claim in the pods’ namespace and uses it to find a persistent volume capable of backing the claim. The volume is then mounted on the host and attached to the pod.</p> -<p>To create a pod that utilizes a PVC, use the following yaml definition:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/mnt/share</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span></code></pre></div><h2 id="storage-classes" >Storage Classes -<span> - <a href="#storage-classes"> - <svg viewBox="0 0 28 23" height="100%" width="19" xmlns="http://www.w3.org/2000/svg"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2"/></svg> - </a> -</span> -</h2><p>In this article, we will only be referencing Kubernetes storage classes with respect to dynamic provisioners. If you would like to learn more, please reference the Kubernetes docs:</p> -<p><a href="https://bit.ly/3ruJD2A">https://bit.ly/3ruJD2A</a></p> -<p>Storage Classes have many uses. Kubernetes is unopinionated about what a storage class represents. They can be used to represent different characteristics of storage (performance, compression method, file system modes, etc.). Storage Classes can also be used to provision persistent volumes dynamically, which will be the focus of this article.</p> -<p>Storage classes are often packaged with CSI drivers. Each StorageClass contains the fields “provisioner”, “parameters”, and “reclaimPolicy”. The provisioner field is used to determine what CSI driver is used for provisioning volumes.</p> -<p>This is an example of the storage class packaged with the AzureFiles CSI driver:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">StorageClass</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">storage.k8s.io/v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azurefileshare</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">provisioner</span>: <span style="color:#ae81ff">file.csi.azure.com</span> <span style="color:#75715e"># replace with &#34;kubernetes.io/azure-file&#34; if aks version is less than 1.21</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">mountOptions</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">dir_mode=0777</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">file_mode=0777</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">uid=0</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">gid=0</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">mfsymlinks</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">cache=strict</span> -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">actimeo=30</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">parameters</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">skuName</span>: <span style="color:#ae81ff">Standard_LRS</span> -</span></span></code></pre></div><p>You can see in the above manifest that the provisioner is set to ‘file.csi.azure.com.’ When a pod uses a PVC in its manifest that references this storage class, the provisioner will dynamically manage the underlying storage.</p> -<p>The name of the storageClass is referenced in the persistentVolumeClaim:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">PersistentVolumeClaim</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">accessModes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">ReadWriteMany</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">resources</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">requests</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storage</span>: <span style="color:#ae81ff">8Gi</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">storageClassName</span>: <span style="color:#ae81ff">azurefileshare</span> -</span></span></code></pre></div><p>You could then reference this PVC in a pod:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-YAML" data-lang="YAML"><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-pd</span> -</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">image</span>: <span style="color:#ae81ff">k8s.gcr.io/test-webserver</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">test-container</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/mnt/share</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>: -</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">cache-volume</span> -</span></span><span style="display:flex;"><span> <span style="color:#f92672">persistentVolumeClaim</span>: -</span></span><span style="display:flex;"><span> <span style="color:#f92672">claimName</span>: <span style="color:#ae81ff">azfileshare</span> -</span></span></code></pre></div><p>That concludes this article. I know that is a lot of information! As always, if you have any questions or comments, please reach out.</p> - + http://localhost:1313/posts/2022-03-01-kubernetes-storage-simplified/ + In this blog post, we will attempt to explain the current storage options that exist in Kubernetes. If you are new to Kubernetes, learning about its capabilities of managing the application state can be a daunting task. Container images are built-in layers, with the runtime layer being writable. However, any files on this writable layer are only available for the container’s lifetime. We can mount a volume to a directory inside the container to have persistent data. - diff --git a/public/tags/storage/page/1/index.html b/public/tags/storage/page/1/index.html index 95b6bcdb..eb05340d 100644 --- a/public/tags/storage/page/1/index.html +++ b/public/tags/storage/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/storage/ - + http://localhost:1313/tags/storage/ + - + diff --git a/public/tags/tools/index.html b/public/tags/tools/index.html index 27a20ddc..f015593e 100644 --- a/public/tags/tools/index.html +++ b/public/tags/tools/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Tools · GeekyRyan + - - -Tools - GeekyRyan - - - - - + - - - - + + + - - - - - + + + + + + + + + - - - - - - - - - + + + + - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,602 +79,181 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - - - - - - -
    -
    - -

    Tag: Tools

    - - - -
    -
    -
    -

    Cisco AnyConnect &#8211; VPN Establishment Capability from a Remote Desktop is Disabled

    -
    - -
    - - -
    - I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution. -Upon installation, AnyConnect pulls down a profile from the ASA containing several settings. This profile is in xml format and is located (on a Windows machine) at %programdata%CiscoCisco AnyConnect Secure Mobility ClientProfileAnyConnectProfile.xsd. -To resolve this issue and connect to your VPN, open this file with notepad (or any text editor, run as admin), search for the “WindowsVPNEstablishment” tag, and modify the value. -
    - - -
    - Read more -
    - - - - - - - - - -
    - - - -
    -
    -
    -

    Script to Move All Disabled AD Objects to a Specified OU

    -
    - -
    - - -
    - The title says it all. This script will move all disabled AD objects to a specified OU. This script accepts parameters that will allow you to specify whether you want to move Users or Computers and the destination OU. It also accepts a “test mode” parameter that will run the script and output the results, without actually modifying Active Directory. -This is revision 1 of the script. There are still several improvements I would like to make, including better error handling and recovery. -
    - - -
    - Read more -
    - - - - - - - -
    - -
    -
    -
    -

    Script for Setting the License for Multiple Office 365 User Accounts

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Tag: Tools +

    +
    + +
    +
  • + 2015-03-09 + Ping Sweeping with FPing +
  • -
    -
    -
    -

    Script for Querying All AD Computers Time Source

    -
    - -
    + + - -
    - This script will iterate through all computers in Active Directory and return the configured time server for each computer. -<# .SYNOPSIS Get time source for all computers in domain .EXAMPLE Get-TimeSource .NOTES Author: Ryan Nemeth - RyanNemeth@live.com Site: http://www.geekyryan.com .LINK http://www.geekyryan.com .DESCRIPTION This function will iterate through all computers/servers in a domain and return the time source for each. #> Write-Host -foregroundcolor Red -BackgroundColor black "This script must be run on a domain controller and requires that the AD Powershell module be installed" $module = Get-Module -ListAvailable | Select-Object -ExpandProperty Name if($module -notcontains "ActiveDirectory") { Write-Host -foregroundcolor red -backgroundcolor black "***Active Directory Powershell Module Not Found***" } else { Write-Host -foregroundcolor yellow "Found Active Directory Powershell Module. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Ping Sweeping with FPing

    -
    -
    +
    +
    + © -
    - I generally use NMAP for any type of host discovery, but recently started experimenting with FPing. One thing I found is that, when performing a ping sweep, not only do I see the hosts that replied to the ping, but FPing also sends any unreachable IP addresses to stdout (which is super annoying and ugly if you ask me…). -Anyway, after a bit of research, I found a nifty way to suppress these messages. -
    + 2012 - + 2024 + Ryan Nemeth + · -
    - Read more -
    - - - - + Powered by Hugo & Coder. +
    +
    +
    - + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/tags/tools/index.xml b/public/tags/tools/index.xml index 00925f00..03f760c8 100644 --- a/public/tags/tools/index.xml +++ b/public/tags/tools/index.xml @@ -2,125 +2,53 @@ Tools on GeekyRyan - https://rnemeth90.github.io/tags/tools/ - GeekyRyan (Tools) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/tools/ + Recent content in Tools on GeekyRyan + Hugo + en Wed, 07 Oct 2020 13:28:00 +0000 - - - - + Cisco AnyConnect &#8211; VPN Establishment Capability from a Remote Desktop is Disabled - https://rnemeth90.github.io/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ + http://localhost:1313/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ Wed, 07 Oct 2020 13:28:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ - <p>I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution.</p> -<p><a href="https://lh3.googleusercontent.com/-BYApW8vZjV8/X33B2Or4D7I/AAAAAAAAxuY/hWQwpE-fqo4xInAsx9vyUvzDJXqxe68QQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-16.png" alt=""></a></p> -<p>Upon installation, AnyConnect pulls down a profile from the ASA containing several settings. This profile is in xml format and is located (on a Windows machine) at %programdata%CiscoCisco AnyConnect Secure Mobility ClientProfileAnyConnectProfile.xsd.</p> -<p>To resolve this issue and connect to your VPN, open this file with notepad (or any text editor, run as admin), search for the “WindowsVPNEstablishment” tag, and modify the value. The default value is “LocalUsersOnly”, you will need to change it to “AllowRemoteUsers”. Save and close the file, then restart the machine.</p> -<p>BEFORE:</p> -<p><a href="https://lh3.googleusercontent.com/-izGUUyhtWyM/X33Bh8YdqGI/AAAAAAAAxuQ/rBbXsqWhe5wZYoGmjXwyyidGmu1kCNVmgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-17.png" alt=""></a></p> -<p>AFTER:</p> -<p><a href="https://lh3.googleusercontent.com/-wFFu1JOXymQ/X33CVp0cImI/AAAAAAAAxug/fibXC6JHmkkilFtWv8641x20flapCibYACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-18.png" alt=""></a></p> - + http://localhost:1313/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ + I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution. Upon installation, AnyConnect pulls down a profile from the ASA containing several settings. This profile is in xml format and is located (on a Windows machine) at %programdata%CiscoCisco AnyConnect Secure Mobility ClientProfileAnyConnectProfile.xsd. To resolve this issue and connect to your VPN, open this file with notepad (or any text editor, run as admin), search for the “WindowsVPNEstablishment” tag, and modify the value. - New Script: BulkAdd-SpamFilterWhitelist.ps1 - https://rnemeth90.github.io/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ + http://localhost:1313/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ Mon, 26 Jun 2017 22:16:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ - <p>This script is capable of adding a list of domains to an Exchange Online Spam Filter policy. It can be downloaded from TechNet or Github.</p> -<p><a href="https://github.com/rnemeth90/PowerShell/blob/master/BulkAdd-SpamFilterWhitelist.ps1">Github</a></p> -<p><a href="https://gallery.technet.microsoft.com/BulkAdd-SpamFilterWhitelist-2d2b596a">TechNet</a></p> - + http://localhost:1313/posts/2017-06-26-new-script-bulkadd-spamfilterwhitelist/ + This script is capable of adding a list of domains to an Exchange Online Spam Filter policy. It can be downloaded from TechNet or Github. Github TechNet - Script to Move All Disabled AD Objects to a Specified OU - https://rnemeth90.github.io/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ + http://localhost:1313/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ Thu, 06 Oct 2016 03:03:00 +0000 - - https://rnemeth90.github.io/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ - <p>The title says it all. This script will move all disabled AD objects to a specified OU. This script accepts parameters that will allow you to specify whether you want to move Users or Computers and the destination OU. It also accepts a “test mode” parameter that will run the script and output the results, without actually modifying Active Directory.</p> -<p>This is revision 1 of the script. There are still several improvements I would like to make, including better error handling and recovery.</p> -<p>If you have any suggestions or requests, please leave a comment.</p> -<p><a href="https://drive.google.com/open?id=0B2K6VOnt6zeXMVFleWZISHZBTnc">Download Here</a></p> - + http://localhost:1313/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ + The title says it all. This script will move all disabled AD objects to a specified OU. This script accepts parameters that will allow you to specify whether you want to move Users or Computers and the destination OU. It also accepts a “test mode” parameter that will run the script and output the results, without actually modifying Active Directory. This is revision 1 of the script. There are still several improvements I would like to make, including better error handling and recovery. - Script for Setting the License for Multiple Office 365 User Accounts - https://rnemeth90.github.io/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ + http://localhost:1313/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ Mon, 11 Apr 2016 01:25:00 +0000 - - https://rnemeth90.github.io/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ - <p>A script for setting the Office 365 license for multiple users. Requires a CSV file named users.csv. This file must in the same directory as the script. The CSV file must contain three columns. The title of the columns should be UPN, UsageLocation, and SKU.</p> -<p><a href="https://drive.google.com/open?id=0B2K6VOnt6zeXZ2Z6OFZhZVoyenc">BulkSet-MsolUserLicense.ps1</a></p> - + http://localhost:1313/posts/2016-04-11-script-for-setting-the-license-for-multiple-office-365-user-accounts/ + A script for setting the Office 365 license for multiple users. Requires a CSV file named users.csv. This file must in the same directory as the script. The CSV file must contain three columns. The title of the columns should be UPN, UsageLocation, and SKU. BulkSet-MsolUserLicense.ps1 - Script for Querying All AD Computers Time Source - https://rnemeth90.github.io/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ + http://localhost:1313/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ Tue, 01 Sep 2015 21:05:00 +0000 - - https://rnemeth90.github.io/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ - <p>This script will iterate through all computers in Active Directory and return the configured time server for each computer.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span><span style="color:#75715e">&lt;# -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">SYNOPSIS</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Get time source for all computers in domain -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">EXAMPLE</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Get-TimeSource -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">NOTES</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Author: Ryan Nemeth - RyanNemeth@live.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Site: http://www.geekyryan.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">LINK</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> http://www.geekyryan.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">DESCRIPTION</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> This function will iterate through all computers/servers in a domain and return the time source -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> for each. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#&gt;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Write-Host -foregroundcolor Red -BackgroundColor black <span style="color:#e6db74">&#34;This script must be run on a domain controller and requires that the AD Powershell module be installed&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$module = Get-Module -ListAvailable | Select-Object -ExpandProperty Name -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span>($module <span style="color:#f92672">-notcontains</span> <span style="color:#e6db74">&#34;ActiveDirectory&#34;</span>) { -</span></span><span style="display:flex;"><span> Write-Host -foregroundcolor red -backgroundcolor black <span style="color:#e6db74">&#34;***Active Directory Powershell Module Not Found***&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span> { -</span></span><span style="display:flex;"><span> Write-Host -foregroundcolor yellow <span style="color:#e6db74">&#34;Found Active Directory Powershell Module. Importing...&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Import-Module ActiveDirectory -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$computers = get-adcomputer -filter * | Select-Object -ExpandProperty Name -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span>($computer <span style="color:#66d9ef">in</span> $computers) { -</span></span><span style="display:flex;"><span> $tm_source = w32tm /query /computer<span style="color:#960050;background-color:#1e0010">:</span>$computer /source -</span></span><span style="display:flex;"><span> write-host <span style="color:#e6db74">&#34;The time source for&#34;</span> $computer <span style="color:#e6db74">&#34;is&#34;</span> $tm_source -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><img src="https://github.com/rnemeth90/PowerShell/blob/master/NTP/Get-TimeSource.ps1" alt=""></p> - + http://localhost:1313/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ + This script will iterate through all computers in Active Directory and return the configured time server for each computer. &lt;# .SYNOPSIS Get time source for all computers in domain .EXAMPLE Get-TimeSource .NOTES Author: Ryan Nemeth - RyanNemeth@live.com Site: http://www.geekyryan.com .LINK http://www.geekyryan.com .DESCRIPTION This function will iterate through all computers/servers in a domain and return the time source for each. #&gt; Write-Host -foregroundcolor Red -BackgroundColor black &#34;This script must be run on a domain controller and requires that the AD Powershell module be installed&#34; $module = Get-Module -ListAvailable | Select-Object -ExpandProperty Name if($module -notcontains &#34;ActiveDirectory&#34;) { Write-Host -foregroundcolor red -backgroundcolor black &#34;***Active Directory Powershell Module Not Found***&#34; } else { Write-Host -foregroundcolor yellow &#34;Found Active Directory Powershell Module. - Ping Sweeping with FPing - https://rnemeth90.github.io/posts/2015-03-09-ping-sweeping-with-fping/ + http://localhost:1313/posts/2015-03-09-ping-sweeping-with-fping/ Mon, 09 Mar 2015 01:08:00 +0000 - - https://rnemeth90.github.io/posts/2015-03-09-ping-sweeping-with-fping/ - <p>I generally use NMAP for any type of host discovery, but recently started experimenting with FPing. One thing I found is that, when performing a ping sweep, not only do I see the hosts that replied to the ping, but FPing also sends any unreachable IP addresses to stdout (which is super annoying and ugly if you ask me…).</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h04_50.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h04_50.png" alt=""></a></p> -<p>Anyway, after a bit of research, I found a nifty way to suppress these messages. Linux allows us to redirect all error messages to /dev/null. So instead of just running the vanilla fping -a -g…. you would run the program and output all error messages /dev/null, like so:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h07_14.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/03/2015-03-08_21h07_14.png" alt=""></a></p> - + http://localhost:1313/posts/2015-03-09-ping-sweeping-with-fping/ + I generally use NMAP for any type of host discovery, but recently started experimenting with FPing. One thing I found is that, when performing a ping sweep, not only do I see the hosts that replied to the ping, but FPing also sends any unreachable IP addresses to stdout (which is super annoying and ugly if you ask me…). Anyway, after a bit of research, I found a nifty way to suppress these messages. - diff --git a/public/tags/tools/page/1/index.html b/public/tags/tools/page/1/index.html index 9e393edd..8b764875 100644 --- a/public/tags/tools/page/1/index.html +++ b/public/tags/tools/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/tools/ - + http://localhost:1313/tags/tools/ + - + diff --git a/public/tags/url/index.html b/public/tags/url/index.html new file mode 100644 index 00000000..8fe924b2 --- /dev/null +++ b/public/tags/url/index.html @@ -0,0 +1,239 @@ + + + + + Tag: Url · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    +
    +

    + Tag: Url +

    +
    + + + + + + + + + +
    + + +
    + +
    +
    + © + + 2012 - + + 2024 + Ryan Nemeth + · + + Powered by Hugo & Coder. + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/tags/url/index.xml b/public/tags/url/index.xml new file mode 100644 index 00000000..05845948 --- /dev/null +++ b/public/tags/url/index.xml @@ -0,0 +1,26 @@ + + + + Url on GeekyRyan + http://localhost:1313/tags/url/ + Recent content in Url on GeekyRyan + Hugo + en + Wed, 27 Mar 2024 00:00:00 +0000 + + + Detecting MIME Types in Go + http://localhost:1313/posts/2024-03-27-golang-detect-file-type/ + Wed, 27 Mar 2024 00:00:00 +0000 + http://localhost:1313/posts/2024-03-27-golang-detect-file-type/ + Introduction Link to heading Knowing the type of a file you&rsquo;re working with is not just a matter of curiosity — it&rsquo;s often a necessity. This is especially true when you&rsquo;re deciding whether or not a particular operation can be carried out on that file. Go, with its comprehensive standard library, offers a straightforward approach to identifying a file&rsquo;s MIME type, ensuring that developers have the tools they need to make informed decisions about file manipulation. + + + Validating URLs with Go + http://localhost:1313/posts/2023-12-12-golang-url-validation/ + Tue, 19 Dec 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-12-12-golang-url-validation/ + Introduction Link to heading In this post, we&rsquo;ll take a quick look at URL validation using Golang. It&rsquo;s common to implement URL validation as a task within a HTTP request pipeline, typically as middleware. There are many different definitions of &ldquo;validation&rdquo;. For the purpose of this article, we will simply validate that a URL conforms to a particular text pattern. I often see people (mistakenly) use URL and URI interchangeably. + + + diff --git a/public/tags/url/page/1/index.html b/public/tags/url/page/1/index.html new file mode 100644 index 00000000..db409638 --- /dev/null +++ b/public/tags/url/page/1/index.html @@ -0,0 +1,10 @@ + + + + http://localhost:1313/tags/url/ + + + + + + diff --git a/public/tags/vmss/index.html b/public/tags/vmss/index.html index 311931a6..086ded29 100644 --- a/public/tags/vmss/index.html +++ b/public/tags/vmss/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: VMSS · GeekyRyan + - - -VMSS - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,292 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Tag: VMSS

    - - - -
    -
    -
    -

    Azure VM Scale Set &#8211; Get Instance IP Address

    -
    -
    +
    +
    + © -
    - If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal. -There are a few options we have for retrieving information about a VMSS and its instances without using the Azure Portal. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/vmss/index.xml b/public/tags/vmss/index.xml index 52e857cd..22127bc6 100644 --- a/public/tags/vmss/index.xml +++ b/public/tags/vmss/index.xml @@ -2,29 +2,18 @@ VMSS on GeekyRyan - https://rnemeth90.github.io/tags/vmss/ - GeekyRyan (VMSS) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/vmss/ + Recent content in VMSS on GeekyRyan + Hugo + en Thu, 19 Nov 2020 18:07:00 +0000 - - - - + Azure VM Scale Set &#8211; Get Instance IP Address - https://rnemeth90.github.io/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ + http://localhost:1313/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ Thu, 19 Nov 2020 18:07:00 +0000 - - https://rnemeth90.github.io/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ - <p>If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal.</p> -<p>There are a few options we have for retrieving information about a VMSS and its instances without using the Azure Portal. We can use PowerShell or the Azure CLI. Being that I am constantly flipping between Windows and Linux, I will detail both here.</p> -<p>You will need to have the AZ module installed. To install this module, simple open PowerShell (as admin) and type in “Install-Module -Name az”. To get the IP address of the instances within a scale set, use the following script:</p> -<p><a href="https://github.com/rnemeth90/Get-VmssInstanceIpAddress">https://github.com/rnemeth90/Get-VmssInstanceIpAddress</a></p> -<p>You can also use the Azure CLI to obtain individual instance IP addresses. This method is much simpler than PowerShell, and only requires one line of code:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>az vmss nic list –resource-group myResourceGroup –vmss-name myVmss | grep –w “privateIpAddress” -</span></span></code></pre></div> + http://localhost:1313/posts/2020-11-19-azure-vm-scale-set-get-instance-ip/ + If you are using VM Scale Sets in Azure, you know how important it can be to quickly obtain an instance IP address. This can of course be done using the Azure Portal. However, I am often working in a shell or VSCode, and I do not want to leave the comfort of my shell to login to the portal. There are a few options we have for retrieving information about a VMSS and its instances without using the Azure Portal. - diff --git a/public/tags/vmss/page/1/index.html b/public/tags/vmss/page/1/index.html index 2769dd7a..46edf0ea 100644 --- a/public/tags/vmss/page/1/index.html +++ b/public/tags/vmss/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/vmss/ - + http://localhost:1313/tags/vmss/ + - + diff --git a/public/tags/vmware/index.html b/public/tags/vmware/index.html index 176ec556..a20d5377 100644 --- a/public/tags/vmware/index.html +++ b/public/tags/vmware/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Vmware · GeekyRyan + - - -vmware - GeekyRyan + - + + + - - - + + + - + + + + + + - - - + + + + - - - - - - - - - - - - - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,515 +79,176 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - -
    -
    - -

    Tag: vmware

    - - - -
    -
    -
    -

    Reset GRUB/root Password for vCenter/PSC Appliance

    -
    - -
    - - -
    - In Redhat/Fedora/Cent, GRUB can be protected by running the grub-md5-crypt command and pasting the outputted password hash into the grub.conf file. vSphere 6.0 password protects grub by default. If you change the root password in the VAMI, the GRUB password is changed to match. If you do not change the root password, the GRUB password is “vmware”. -To reset the GRUB password, we need to boot into a Cent or Redhat live CD. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    Could not connect to VMware Directory Service via LDAP when Deploying New vCenter Appliance

    -
    - -
    - - -
    - Problem: -Deploying a brand new vCSA 6.7 appliance results in the following error during the second stage of the deployment. -Solution: -This problem is almost always caused by DNS resolution. Once you create the appropriate A and PTR record for your appliance on a LOCAL DNS server, you should be to successfully complete the deployment. Local DNS resolution is required, you cannot use a public DNS server while installing vCenter. For example, 8. -
    - - -
    - Read more -
    - - - - - - - -
    - -
    -
    -
    -

    Azure Site Recovery &#8211; VMware-to-Azure: Wrong IP address discovered for VM

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Tag: Vmware +

    +
    + + + - https://rnemeth90.github.io/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ - Ryan - - -
    - - - - - - -
    -
    - -
    - -
    -
    -
    -

    Remove Stubborn PSC or vCenter Appliance from an SSO Domain

    -
    - -
    - -
    - While attempting to decommission one of our vCenter sites, I ran into an issue removing one of the PSCs. This site consisted of two PSCs and one vCenter appliance. I removed the first PSC from the SSO domain successfully, and then removed the vCenter appliance. Things became a little tricky during the removal of the final PSC. This PSC did not get removed even after running the cmsso-util command. This article will detail the steps I took in decommissioning the site, as well as removing the stubborn PSC. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Running vSphere in VMware Workstation 12

    -
    - -
    - - -
    - In this post I’ll be walking through how to run a vSphere lab in VMware Workstation. I recently decided to obtain VCP6-DCV. Rather than driving up my electric bill like I’ve done in the past using physical servers, I’m attempting to run the entire lab on my workstation and a Synology NAS. -If you’ve ever installed ESXi, installing it in Workstation will be a familiar process for you. VMware tools is included in the installation disc, which makes installing ESXi in Workstation dramatically easier than it used to be. -
    +
    +
    + © + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - +
    +
    -
    - https://rnemeth90.github.io/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/vmware/index.xml b/public/tags/vmware/index.xml index 5952a932..5838f1b7 100644 --- a/public/tags/vmware/index.xml +++ b/public/tags/vmware/index.xml @@ -1,146 +1,47 @@ - vmware on GeekyRyan - https://rnemeth90.github.io/tags/vmware/ - GeekyRyan (vmware) - Hugo -- gohugo.io - en-us + Vmware on GeekyRyan + http://localhost:1313/tags/vmware/ + Recent content in Vmware on GeekyRyan + Hugo + en Sat, 31 Oct 2020 01:22:00 +0000 - - - - + Reset GRUB/root Password for vCenter/PSC Appliance - https://rnemeth90.github.io/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ + http://localhost:1313/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ Sat, 31 Oct 2020 01:22:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ - <p>In Redhat/Fedora/Cent, GRUB can be protected by running the grub-md5-crypt command and pasting the outputted password hash into the grub.conf file. vSphere 6.0 password protects grub by default. If you change the root password in the VAMI, the GRUB password is changed to match. If you do not change the root password, the GRUB password is “vmware”.</p> -<p>To reset the GRUB password, we need to boot into a Cent or Redhat live CD. The ISO can be obtained here: <a href="https://www.centos.org/download/">https://www.centos.org/download/</a>. Its best to upload the ISO to a datastore that the appliance has access to.</p> -<p>Stop the appliance and attach the ISO:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image.png" alt=""></p> -<p>Be sure to select the “Connect at Power On” option. Boot the VM into the ISO and select the “Troubleshooting” option.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-1.png" alt=""> -Next, choose “Rescure a Red hat (or CentOS depending on your ISO) Enterprise Linux System”</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-2.png" alt=""></p> -<p>Select “Continue” to mount the VCSA 6.0’s root filesystem in Read/write mode under /mnt/sysimage. RHEL 7.2 is capable to detect the VCSA’s root volume and mounts it.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-3.png" alt=""></p> -<p>The VCSA root filesystem is mounted under /mnt/sysimage and you can now access (and modify) it using the shell. Navigate to /mnt/sysimage/boot and list the contents. You’ll see we now have access to the grub directory:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-4.png" alt=""></p> -<p>cd to the grub directory and list the contents. Look for a file called “menu.lst”. This file holds the grub boot loader password. Open this file with vi by typing “vi menu.lst”. Navigate to the line beginning with “password” using the arrow keys, and then type “dd” to remove the line.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-5.png" alt=""> -You can then save the file by pressing “:wq” (without quotes). You can now cat the file and see that the password has been removed.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-6.png" alt=""></p> -<p>Exit the shell (this will reboot the server). Detach the ISO and boot the appliance. Once the system is booted, stop the VCSA in the GRUB menu (by pressing the escape key during boot) to break the OS root password.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-7.png"></a> -Press “e” to edit the boot commands for the kernel.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-8.png" alt=""></p> -<p>Append “init=/bin/bash” to the line in this step and press enter.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-9.png" alt=""></p> -<p>Press “b” to boot the system.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-10.png" alt=""></p> -<p>You will now boot into a bash shell where you can set the root password.</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-11.png" alt=""></p> -<p>Once this is done, exit the shell by typing “exit”. You can now boot the appliance and login with your new root password.</p> - + http://localhost:1313/posts/2020-10-31-reset-grubroot-password-for-vcenterpsc/ + In Redhat/Fedora/Cent, GRUB can be protected by running the grub-md5-crypt command and pasting the outputted password hash into the grub.conf file. vSphere 6.0 password protects grub by default. If you change the root password in the VAMI, the GRUB password is changed to match. If you do not change the root password, the GRUB password is “vmware”. To reset the GRUB password, we need to boot into a Cent or Redhat live CD. - Could not connect to VMware Directory Service via LDAP when Deploying New vCenter Appliance - https://rnemeth90.github.io/posts/2020-10-28-could-not-connect-to-vmware-directory/ + http://localhost:1313/posts/2020-10-28-could-not-connect-to-vmware-directory/ Wed, 28 Oct 2020 13:51:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-28-could-not-connect-to-vmware-directory/ - <p>Problem:</p> -<p>Deploying a brand new vCSA 6.7 appliance results in the following error during the second stage of the deployment.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h29_02.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h29_02.png" alt=""></a><span style="text-align: left;"> </span></p> -<p>Solution:</p> -<p>This problem is almost always caused by DNS resolution. Once you create the appropriate A and PTR record for your appliance on a LOCAL DNS server, you should be to successfully complete the deployment. Local DNS resolution is required, you cannot use a public DNS server while installing vCenter. For example, 8.8.8.8 will not work.</p> -<p>Since you have already completed Stage 1 of the deployment, you can login to the appliance via SSH and update the DNS settings. This will only work if you chose to enable SSH during Stage 2 of the deployment.</p> -<p>SSH to the appliance and run “/opt/vmware/share/vami/vami_config_net” (without quotes). Choose option 4 to update DNS settings and option 3 to update the hostname (if necessary). The deployment wizard states that a hostname is optional, but it is actually required. I have never had a successful deployment without specifying the hostname.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h33_18.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h33_18.png" alt=""></a></p> -<p>You can then verify the DNS settings have been updated in the resolve.conf:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h33_57.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_07h33_57.png" alt=""></a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_08h47_36.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/2020-10-28_08h47_36.png" alt=""></a></p> - + http://localhost:1313/posts/2020-10-28-could-not-connect-to-vmware-directory/ + Problem: Deploying a brand new vCSA 6.7 appliance results in the following error during the second stage of the deployment. Solution: This problem is almost always caused by DNS resolution. Once you create the appropriate A and PTR record for your appliance on a LOCAL DNS server, you should be to successfully complete the deployment. Local DNS resolution is required, you cannot use a public DNS server while installing vCenter. For example, 8. - Azure Site Recovery &#8211; VMware-to-Azure: Wrong IP address discovered for VM - https://rnemeth90.github.io/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ + http://localhost:1313/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ Tue, 21 Aug 2018 17:26:00 +0000 - - https://rnemeth90.github.io/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ - <p>When replicating virtual machines from VMware to Azure using Site Recovery, you may encounter an issue where the Configuration server discovers the wrong IP address for a VM. This can be caused by stale entries within the infrastructurevms MySQL table that is used by ASR to track VM attributes.</p> -<p>To resolve this issue, you first need to disable replication for the VM in the Azure Portal.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-21_13h20_26.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2018/08/2018-08-21_13h20_26.png" alt=""></a></p> -<p>Next, login to your ASR Configuration Server and open a CMD prompt as administrator. Browse to the bin directory for your ASR installation. For example, in my case ASR is installed on the E: partition under the following directory:</p> -<p>E:\Program Files (x86)Microsoft Azure Site Recoveryhomesvsystemsbin</p> -<p>Type in this command to remove the VM from the ASR database (replace IP address with the IP of your VM):</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-perl" data-lang="perl"><span style="display:flex;"><span>perl Unregister<span style="color:#f92672">-</span>ASRComponent<span style="color:#f92672">.</span>pl <span style="color:#f92672">-</span>IPAddress <span style="color:#ae81ff">10.0.0.4</span> <span style="color:#f92672">-</span>Component Source -</span></span></code></pre></div><p>That’s it. You should now be able to reconfigure replication for the VM, and ASR will discover the correct info about the VM.</p> - + http://localhost:1313/posts/2018-08-21-azure-site-recovery-vmware-to-azure/ + When replicating virtual machines from VMware to Azure using Site Recovery, you may encounter an issue where the Configuration server discovers the wrong IP address for a VM. This can be caused by stale entries within the infrastructurevms MySQL table that is used by ASR to track VM attributes. To resolve this issue, you first need to disable replication for the VM in the Azure Portal. Next, login to your ASR Configuration Server and open a CMD prompt as administrator. - Remove Stubborn PSC or vCenter Appliance from an SSO Domain - https://rnemeth90.github.io/posts/2017-11-08-remove-stubborn-psc-or-vcenter/ + http://localhost:1313/posts/2017-11-08-remove-stubborn-psc-or-vcenter/ Wed, 08 Nov 2017 07:56:00 +0000 - - https://rnemeth90.github.io/posts/2017-11-08-remove-stubborn-psc-or-vcenter/ - <p>While attempting to decommission one of our vCenter sites, I ran into an issue removing one of the PSCs. This site consisted of two PSCs and one vCenter appliance. I removed the first PSC from the SSO domain successfully, and then removed the vCenter appliance. Things became a little tricky during the removal of the final PSC. This PSC did not get removed even after running the cmsso-util command. This article will detail the steps I took in decommissioning the site, as well as removing the stubborn PSC.</p> -<p>First, we need to check if vCenter is currently using the PSC we plan on decommissioning. If it is, we need to use the cmsso-util command to redirect vCenter to a different PSC. Instructions for redirecting vCenter can be found here: <a href="https://kb.vmware.com/s/article/2113917?language=en_US">https://kb.vmware.com/s/article/2113917?language=en_US</a></p> -<p>To check what PSC your vCSA is currently pointing to, browse to the Advanced Settings for the vCSA in the vSphere Web Client. Filter by this key: config.vpxd.sso.admin.uri</p> -<p>To remove a PSC or vCSA from an SSO domain, connect to a PSC via SSH and run these commands:</p> -<p>To remove a PSC from the vSphere SSO domain:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>cmsso-util unregister –node-pnid psc01.ad.vcplab.local –username administrator@your<span style="color:#ae81ff">\_</span>domain<span style="color:#ae81ff">\_</span>name –passwd vCenter<span style="color:#ae81ff">\_</span>Single<span style="color:#ae81ff">\_</span>Sign<span style="color:#ae81ff">\_</span>On<span style="color:#ae81ff">\_</span>password -</span></span></code></pre></div><p>To remove a vCSA from the vSphere SSO domain:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>cmsso-util unregister –node-pnid vcsa.ad.vcplab.local –username administrator@your<span style="color:#ae81ff">\_</span>domain<span style="color:#ae81ff">\_</span>name –passwd vCenter<span style="color:#ae81ff">\_</span>Single<span style="color:#ae81ff">\_</span>Sign<span style="color:#ae81ff">\_</span>On<span style="color:#ae81ff">\_</span>password -</span></span></code></pre></div><p>After running these commands, delete the virtual appliances. You can also verify the appliances have been removed by browsing to Administration &gt; System Configuration &gt; Nodes in the vSphere Web Client.</p> -<p>If cmsso-util fails to remove any of the nodes, you can use this command to force the removal:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>vdcleavefed -h vcsa.ad.vcplab.local -u Administrator -w Passw0rd! -</span></span></code></pre></div><p>Upon successful completion, you should see something like this:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>/usr/lib/vmware-vmdir/bin/vdcleavefed -h vcsa.ad.vcplab.local -u administrator* password: -</span></span><span style="display:flex;"><span>vdcleavefd offline <span style="color:#66d9ef">for</span> server vcsa.ad.vcplab.local -</span></span><span style="display:flex;"><span>Leave federation cleanup <span style="color:#66d9ef">done</span> -</span></span></code></pre></div><p>When specifying the username, use the SSO admin (administrator). However, do not use the full UPN (<a href="mailto:administrator@vsphere.local">administrator@vsphere.local</a>). Doing so will cause the command to fail.</p> - + http://localhost:1313/posts/2017-11-08-remove-stubborn-psc-or-vcenter/ + While attempting to decommission one of our vCenter sites, I ran into an issue removing one of the PSCs. This site consisted of two PSCs and one vCenter appliance. I removed the first PSC from the SSO domain successfully, and then removed the vCenter appliance. Things became a little tricky during the removal of the final PSC. This PSC did not get removed even after running the cmsso-util command. This article will detail the steps I took in decommissioning the site, as well as removing the stubborn PSC. - Running vSphere in VMware Workstation 12 - https://rnemeth90.github.io/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/ + http://localhost:1313/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/ Mon, 29 May 2017 01:09:00 +0000 - - https://rnemeth90.github.io/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/ - <p>In this post I’ll be walking through how to run a vSphere lab in VMware Workstation. I recently decided to obtain VCP6-DCV. Rather than driving up my electric bill like I’ve done in the past using physical servers, I’m attempting to run the entire lab on my workstation and a Synology NAS.</p> -<p>If you’ve ever installed ESXi, installing it in Workstation will be a familiar process for you. VMware tools is included in the installation disc, which makes installing ESXi in Workstation dramatically easier than it used to be. . The process is very simple, so I won’t be going through those steps here unless someone asks me to in the comments. I also will not be going through the process of installing Windows Server or configuring a domain controller/DNS/DHCP, as I am sure you have done so in the past if you are reading this.</p> -<p>So that really only leaves us with installing vCenter. Most of the blogs I found for installing vCenter in VMware Workstation 12 were not accurate, and often left me with a broken installation. The process is somewhat straight-forward when deploying from the OVA. Let’s get started.</p> -<p>First, download the OVA for vCenter here: <a href="https://my.vmware.com/web/vmware/details?productId=614&amp;downloadGroup=VC650">Download vCenter</a></p> -<p>Once the download has completed, click File &gt; Open in Workstation. Browse to the OVA, then give your new VM a name and location if necessary. Accept the EULA when prompted.</p> -<p>Be sure to read it! 😎</p> -<p>Once the OVA finishes importing, do not power on the VM! There is some customization we need to do first. Close Workstation if it is open. Browse to the location on your PC that you imported the VM to. I’m using a Windows OS, so I will use File Explorer. Open the .VMX file (use Notepad or another text editor):</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-28_21h00_04.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-28_21h00_04.png" alt=""></a></p> -<p>This is the configuration file for your virtual machine. We can use it to customize the name, IPv4/6 details, DNS domain, etc. Scroll down to the last line of text, and paste this in:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>guestinfo.cis.vmdir.password <span style="color:#f92672">=</span> “vmware!” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.addr.family <span style="color:#f92672">=</span> “ipv4” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.addr <span style="color:#f92672">=</span> “10.0.0.15” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.prefix <span style="color:#f92672">=</span> “24” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.mode <span style="color:#f92672">=</span> “static” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.dns.servers <span style="color:#f92672">=</span> “10.0.0.10” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.net.gateway <span style="color:#f92672">=</span> “10.0.0.1” -</span></span><span style="display:flex;"><span>guestinfo.cis.appliance.root.passwd <span style="color:#f92672">=</span> “vmware!” -</span></span></code></pre></div><p>Customize the above code to your needs. You will likely need to change the IPv4 details. Save the .VMX file and close your text editor. Now you can power on the virtual machine, and vCenter will run through the installation process. The installation can take around 10-15 minute in my experience. You may see generic login screens during the installation of Photon, do not login or interrupt the installation. Once it is complete, you should see the DCUI below:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h11_00.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h11_00.png" alt=""></a></p> -<p>You should now be able to browse to the IP address or DNS name of your vCenter server. Once you complete the configuration, you can login and see the page below: -<a href="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h10_39.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h10_39.png" alt=""></a></p> -<p>In my lab I am running 3 ESXi hosts, 1 Windows Server, and one vCenter server. Plenty to study for the VCP lab.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h11_31.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2017/05/2017-05-24_10h11_31.png" alt=""></a></p> -<p>Good luck and be sure to leave a comment if you have any questions!</p> - + http://localhost:1313/posts/2017-05-29-running-vsphere-in-vmware-workstation-12/ + In this post I’ll be walking through how to run a vSphere lab in VMware Workstation. I recently decided to obtain VCP6-DCV. Rather than driving up my electric bill like I’ve done in the past using physical servers, I’m attempting to run the entire lab on my workstation and a Synology NAS. If you’ve ever installed ESXi, installing it in Workstation will be a familiar process for you. VMware tools is included in the installation disc, which makes installing ESXi in Workstation dramatically easier than it used to be. - diff --git a/public/tags/vmware/page/1/index.html b/public/tags/vmware/page/1/index.html index 08b2f3c3..93933855 100644 --- a/public/tags/vmware/page/1/index.html +++ b/public/tags/vmware/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/vmware/ - + http://localhost:1313/tags/vmware/ + - + diff --git a/public/tags/wds/index.html b/public/tags/wds/index.html index 9e489136..577501e7 100644 --- a/public/tags/wds/index.html +++ b/public/tags/wds/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: WDS · GeekyRyan + - - -WDS - GeekyRyan - - + + + + - - - - + + + - - - - - + + + + + + + - - - - - - - - - + + + - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,288 +79,156 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - + - - - -
    -
    - -

    Tag: WDS

    - - - -
    -
    -
    -

    WDS Service: The Service did not respond in a timely fashion

    -
    -
    +
    +
    + © -
    - This was a new one for me. Usually WDS is rock solid and it just works. -Anyway, I was getting ready to deploy some servers in my lab and found that I couldn’t get WDS to start on my deployment server. I got this error message when trying to start the service: -I then tried to start the service from the Services console and got this error message: -“This was just working yesterday”, I said to myself. -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    - https://rnemeth90.github.io/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/wds/index.xml b/public/tags/wds/index.xml index 7cecc83a..66db60b6 100644 --- a/public/tags/wds/index.xml +++ b/public/tags/wds/index.xml @@ -2,35 +2,18 @@ WDS on GeekyRyan - https://rnemeth90.github.io/tags/wds/ - GeekyRyan (WDS) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/wds/ + Recent content in WDS on GeekyRyan + Hugo + en Thu, 10 Nov 2016 02:19:00 +0000 - - - - + WDS Service: The Service did not respond in a timely fashion - https://rnemeth90.github.io/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ + http://localhost:1313/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ Thu, 10 Nov 2016 02:19:00 +0000 - - https://rnemeth90.github.io/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ - <p>This was a new one for me. Usually WDS is rock solid and it just works.</p> -<p>Anyway, I was getting ready to deploy some servers in my lab and found that I couldn’t get WDS to start on my deployment server. I got this error message when trying to start the service:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h02_29.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h02_29.png" alt=""></a></p> -<p>I then tried to start the service from the Services console and got this error message:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h02_42.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h02_42.png" alt=""></a></p> -<p>“This was just working yesterday”, I said to myself. What could possibly have happened since yesterday evening that could cause this? I looked in the event log and after scrolling through the Administrative Events, I found this:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h04_33.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h04_33.png" alt=""></a></p> -<p>The solution was so obvious it was staring me in the face, but I wanted to verify first. So I fired up a cmd prompt and ran netstat, and found this:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h06_14.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h06_14.png" alt=""></a></p> -<p>I had installed DHCP on this server the night before and totally forgot about it. Anyway, the solution was simple. I just needed to tell the WDS service to not listen on port 67. To do that, just open the WDS server properties and got to the “DHCP” tab. Then check the box next to “Do not listen on DHCP Ports”.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h08_04.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h08_04.png" alt=""></a></p> -<p>I was then able to start the DHCP service.</p> - + http://localhost:1313/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ + This was a new one for me. Usually WDS is rock solid and it just works. Anyway, I was getting ready to deploy some servers in my lab and found that I couldn’t get WDS to start on my deployment server. I got this error message when trying to start the service: I then tried to start the service from the Services console and got this error message: “This was just working yesterday”, I said to myself. - diff --git a/public/tags/wds/page/1/index.html b/public/tags/wds/page/1/index.html index 666405c8..f5c9884e 100644 --- a/public/tags/wds/page/1/index.html +++ b/public/tags/wds/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/wds/ - + http://localhost:1313/tags/wds/ + - + diff --git a/public/tags/web-development/index.html b/public/tags/web-development/index.html new file mode 100644 index 00000000..562dd62f --- /dev/null +++ b/public/tags/web-development/index.html @@ -0,0 +1,244 @@ + + + + + Tag: Web Development · GeekyRyan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    +
    +

    + Tag: Web Development +

    +
    + + + + + + + + + +
    + + +
    + +
    +
    + © + + 2012 - + + 2024 + Ryan Nemeth + · + + Powered by Hugo & Coder. + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/tags/web-development/index.xml b/public/tags/web-development/index.xml new file mode 100644 index 00000000..30a8fdf0 --- /dev/null +++ b/public/tags/web-development/index.xml @@ -0,0 +1,33 @@ + + + + Web Development on GeekyRyan + http://localhost:1313/tags/web-development/ + Recent content in Web Development on GeekyRyan + Hugo + en + Sat, 29 Jun 2024 00:00:00 +0000 + + + Mounting Multiple Kubernetes Secrets into One Directory + http://localhost:1313/posts/2024-06-29-mount-multiple-kubernetes-secrets-into-one-directory/ + Sat, 29 Jun 2024 00:00:00 +0000 + http://localhost:1313/posts/2024-06-29-mount-multiple-kubernetes-secrets-into-one-directory/ + Introduction Link to heading Combining multiple Kubernetes secrets into a single directory can streamline secret management in your applications. This guide walks you through the process of achieving this in Kubernetes, ensuring efficient and organized secret management. Creating Secrets Link to heading First, create your secrets using the kubectl create secret command: kubectl create secret generic secret-one --from-literal=key1=value1 kubectl create secret generic secret-two --from-literal=key2=value2 Each secret can contain multiple key-value pairs, and you can add more secrets as needed. + + + Detecting MIME Types in Go + http://localhost:1313/posts/2024-03-27-golang-detect-file-type/ + Wed, 27 Mar 2024 00:00:00 +0000 + http://localhost:1313/posts/2024-03-27-golang-detect-file-type/ + Introduction Link to heading Knowing the type of a file you&rsquo;re working with is not just a matter of curiosity — it&rsquo;s often a necessity. This is especially true when you&rsquo;re deciding whether or not a particular operation can be carried out on that file. Go, with its comprehensive standard library, offers a straightforward approach to identifying a file&rsquo;s MIME type, ensuring that developers have the tools they need to make informed decisions about file manipulation. + + + Validating URLs with Go + http://localhost:1313/posts/2023-12-12-golang-url-validation/ + Tue, 19 Dec 2023 00:00:00 +0000 + http://localhost:1313/posts/2023-12-12-golang-url-validation/ + Introduction Link to heading In this post, we&rsquo;ll take a quick look at URL validation using Golang. It&rsquo;s common to implement URL validation as a task within a HTTP request pipeline, typically as middleware. There are many different definitions of &ldquo;validation&rdquo;. For the purpose of this article, we will simply validate that a URL conforms to a particular text pattern. I often see people (mistakenly) use URL and URI interchangeably. + + + diff --git a/public/tags/web-development/page/1/index.html b/public/tags/web-development/page/1/index.html new file mode 100644 index 00000000..f1d42372 --- /dev/null +++ b/public/tags/web-development/page/1/index.html @@ -0,0 +1,10 @@ + + + + http://localhost:1313/tags/web-development/ + + + + + + diff --git a/public/tags/windows-client-os/index.html b/public/tags/windows-client-os/index.html index a86a870d..77b21bda 100644 --- a/public/tags/windows-client-os/index.html +++ b/public/tags/windows-client-os/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Windows Client OS · GeekyRyan + - - -Windows Client OS - GeekyRyan - - - - - - - - - - + - - + + + - - + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,348 +79,161 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    -
    -
    - -

    Tag: Windows Client OS

    - + 2020-10-07 + Cisco AnyConnect &#8211; VPN Establishment Capability from a Remote Desktop is Disabled + +
  • + 2017-06-22 + Windows 8 File History +
  • -
    -
    -
    -

    Cisco AnyConnect &#8211; VPN Establishment Capability from a Remote Desktop is Disabled

    -
    - -
    + + - -
    - I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution. -Upon installation, AnyConnect pulls down a profile from the ASA containing several settings. This profile is in xml format and is located (on a Windows machine) at %programdata%CiscoCisco AnyConnect Secure Mobility ClientProfileAnyConnectProfile.xsd. -To resolve this issue and connect to your VPN, open this file with notepad (or any text editor, run as admin), search for the “WindowsVPNEstablishment” tag, and modify the value. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    Windows 8 File History

    -
    -
    +
    +
    + © -
    - File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - +
    +
    -
    - https://rnemeth90.github.io/posts/2017-06-22-windows-8-file-history-windows-8-file-history/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/windows-client-os/index.xml b/public/tags/windows-client-os/index.xml index 57f80160..6659a035 100644 --- a/public/tags/windows-client-os/index.xml +++ b/public/tags/windows-client-os/index.xml @@ -2,47 +2,25 @@ Windows Client OS on GeekyRyan - https://rnemeth90.github.io/tags/windows-client-os/ - GeekyRyan (Windows Client OS) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/windows-client-os/ + Recent content in Windows Client OS on GeekyRyan + Hugo + en Wed, 07 Oct 2020 13:28:00 +0000 - - - - + Cisco AnyConnect &#8211; VPN Establishment Capability from a Remote Desktop is Disabled - https://rnemeth90.github.io/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ + http://localhost:1313/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ Wed, 07 Oct 2020 13:28:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ - <p>I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution.</p> -<p><a href="https://lh3.googleusercontent.com/-BYApW8vZjV8/X33B2Or4D7I/AAAAAAAAxuY/hWQwpE-fqo4xInAsx9vyUvzDJXqxe68QQCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-16.png" alt=""></a></p> -<p>Upon installation, AnyConnect pulls down a profile from the ASA containing several settings. This profile is in xml format and is located (on a Windows machine) at %programdata%CiscoCisco AnyConnect Secure Mobility ClientProfileAnyConnectProfile.xsd.</p> -<p>To resolve this issue and connect to your VPN, open this file with notepad (or any text editor, run as admin), search for the “WindowsVPNEstablishment” tag, and modify the value. The default value is “LocalUsersOnly”, you will need to change it to “AllowRemoteUsers”. Save and close the file, then restart the machine.</p> -<p>BEFORE:</p> -<p><a href="https://lh3.googleusercontent.com/-izGUUyhtWyM/X33Bh8YdqGI/AAAAAAAAxuQ/rBbXsqWhe5wZYoGmjXwyyidGmu1kCNVmgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-17.png" alt=""></a></p> -<p>AFTER:</p> -<p><a href="https://lh3.googleusercontent.com/-wFFu1JOXymQ/X33CVp0cImI/AAAAAAAAxug/fibXC6JHmkkilFtWv8641x20flapCibYACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-18.png" alt=""></a></p> - + http://localhost:1313/posts/2020-10-07-cisco-anyconnect-vpn-establishment/ + I ran into this issue this morning when attempting to setup a VPN on a Hyper-V virtual machine. After an hour of searching the Google machine and troubleshooting, I came upon this solution. Upon installation, AnyConnect pulls down a profile from the ASA containing several settings. This profile is in xml format and is located (on a Windows machine) at %programdata%CiscoCisco AnyConnect Secure Mobility ClientProfileAnyConnectProfile.xsd. To resolve this issue and connect to your VPN, open this file with notepad (or any text editor, run as admin), search for the “WindowsVPNEstablishment” tag, and modify the value. - Windows 8 File History - https://rnemeth90.github.io/posts/2017-06-22-windows-8-file-history-windows-8-file-history/ + http://localhost:1313/posts/2017-06-22-windows-8-file-history-windows-8-file-history/ Thu, 22 Jun 2017 22:42:00 +0000 - - https://rnemeth90.github.io/posts/2017-06-22-windows-8-file-history-windows-8-file-history/ - <p>File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. To begin using it, connect an external drive and search for File History on the Start Screen:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2014-11-15_14h19_47.png" alt=""></p> -<p>After opening File History, you will see this screen:</p> -<p><img src="https://rnemeth90.github.io/wp-content/uploads/2017/06/2014-11-15_14h20_32.png" alt=""></p> -<p>To enable File History, click the ‘Turn On’ button. You can select the drive you want to use by clicking ‘Select Drive’ on the left hand side from this same screen. The first time you enable File History, it will create a full backup of all files on your computer, except for files that you do not access (system files), and files you have chosen to exclude. From then on, it will create a versioned copy of every file that has changed since the last backup.</p> -<p>You can use a locally attached drive or a network share for File History. To choose how often File History backs up files; choose ‘Advanced Settings’. From here you can also choose how much space on the drive is used, and how long saved versions of files should be kept.</p> -<p>When the total space allocated to File History has been used, the feature will delete the oldest versions of files to make room for newer versions.</p> - + http://localhost:1313/posts/2017-06-22-windows-8-file-history-windows-8-file-history/ + File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. - diff --git a/public/tags/windows-client-os/page/1/index.html b/public/tags/windows-client-os/page/1/index.html index 7f31cfb5..03e18df7 100644 --- a/public/tags/windows-client-os/page/1/index.html +++ b/public/tags/windows-client-os/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/windows-client-os/ - + http://localhost:1313/tags/windows-client-os/ + - + diff --git a/public/tags/windows/index.html b/public/tags/windows/index.html index 1e1de6b1..3b44c908 100644 --- a/public/tags/windows/index.html +++ b/public/tags/windows/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: Windows · GeekyRyan + - - -Windows - GeekyRyan - - - + - - - + + + - - + + + + + + + + + - + + + + - - - - - - - - - - - - - - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,392 +79,166 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - + + + - - - - - - - - -
    -
    - -

    Tag: Windows

    - - - -
    -
    -
    -

    File History

    -
    - -
    - - -
    - File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. -
    - - -
    - Read more -
    - - - +
    + + + +
    + +
    +
    +

    + Tag: Windows +

    +
    + +
    +
  • + 2012-11-15 + User Account Control +
  • -
    -
    -
    -

    User Account Control

    -
    - -
    + + - -
    - Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    User Account Control

    -
    -
    +
    +
    + © -
    - Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - +
    +
    +
    - + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - -
    + + diff --git a/public/tags/windows/index.xml b/public/tags/windows/index.xml index 5f3b7bd4..ef11a03e 100644 --- a/public/tags/windows/index.xml +++ b/public/tags/windows/index.xml @@ -2,70 +2,32 @@ Windows on GeekyRyan - https://rnemeth90.github.io/tags/windows/ - GeekyRyan (Windows) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/windows/ + Recent content in Windows on GeekyRyan + Hugo + en Sat, 15 Nov 2014 20:02:00 +0000 - - - - + File History - https://rnemeth90.github.io/posts/2014-11-15-file-history/ + http://localhost:1313/posts/2014-11-15-file-history/ Sat, 15 Nov 2014 20:02:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-15-file-history/ - <p>File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. To begin using it, connect an external drive and search for File History on the Start Screen:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-15_14h19_47.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-15_14h19_47.png" alt=""></a></p> -<p>After opening File History, you will see this screen:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-15_14h20_32.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-15_14h20_32.png" alt=""></a></p> -<p>To enable File History, click the ‘Turn On’ button. You can select the drive you want to use by clicking ‘Select Drive’ on the left hand side from this same screen. The first time you enable File History, it will create a full backup of all files on your computer, except for files that you do not access (system files), and files you have chosen to exclude. From then on, it will create a versioned copy of every file that has changed since the last backup.</p> -<p>You can use a locally attached drive or a network share for File History. To choose how often File History backs up files; choose ‘Advanced Settings’. From here you can also choose how much space on the drive is used, and how long saved versions of files should be kept.</p> -<p>When the total space allocated to File History has been used, the feature will delete the oldest versions of files to make room for newer versions.</p> - + http://localhost:1313/posts/2014-11-15-file-history/ + File history in Windows 8 allows users to automatically “backup” files that are in their libraries, contacts, favorites, Skydrive, and on the desktop. If the files are lost, they can be quickly restored. You can also restore a file from a specific point in time, being that File History creates a complete history of your files over time. You will need a separate drive other than the one you have Windows 8 installed on to use File History. - User Account Control - https://rnemeth90.github.io/posts/2012-11-15-user-account-control-copy/ + http://localhost:1313/posts/2012-11-15-user-account-control-copy/ Thu, 15 Nov 2012 16:01:00 +0000 - - https://rnemeth90.github.io/posts/2012-11-15-user-account-control-copy/ - <p>Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system.</p> -<p>For a standard user, a token with the most basic privileges is assigned. Administrators have two tokens assigned, the first token contains all privileges usually awarded to an administrator (unrestricted), and the second is similar to that awarded to a basic user. This way, all programs that the administrator runs, including the Windows Shell, are run in basic user mode (this is why administrators still receive UAC prompts, but do not get asked for credentials). When an application requests higher privileges, the higher integrity token is used .</p> -<p>User Account Control prompts each have their own meaning based on the color (blue, grey, yellow, or red. The blue prompt (Figure 1) means that a built in Windows component that is signed by Microsoft is requesting administrative privileges to continue. This prompt has a multicolored shield in the upper left corner. The grey prompt (Figure 2) means a software application that is signed by a third party developer is requesting admin privileges. This prompt has a yellow shield with a black exclamation mark in the upper left corner. The yellow prompt (Figure 3) signifies that a unsigned executable is requesting administrator privileges. This prompt also had a yellow shield with black exclamation mark in the upper left corner, and looks somewhat generic. Finally, the red prompt (Figure 4) means a program that was specifically blocked by an administrator has attempted to run.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BBlue.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BBlue.png" alt=""></a></p> -<p>Figure 1</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BGrey.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BGrey.png" alt=""></a></p> -<p>Figure 2</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BYellow.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BYellow.png" alt=""></a></p> -<p>Figure 3</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BRED.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BRED.png" alt=""></a></p> -<p>Figure 4</p> - + http://localhost:1313/posts/2012-11-15-user-account-control-copy/ + Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system. - User Account Control - https://rnemeth90.github.io/posts/2012-11-15-user-account-control/ + http://localhost:1313/posts/2012-11-15-user-account-control/ Thu, 15 Nov 2012 16:01:00 +0000 - - https://rnemeth90.github.io/posts/2012-11-15-user-account-control/ - <p>Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system.</p> -<p>For a standard user, a token with the most basic privileges is assigned. Administrators have two tokens assigned, the first token contains all privileges usually awarded to an administrator (unrestricted), and the second is similar to that awarded to a basic user. This way, all programs that the administrator runs, including the Windows Shell, are run in basic user mode (this is why administrators still receive UAC prompts, but do not get asked for credentials). When an application requests higher privileges, the higher integrity token is used.</p> -<p>User Account Control prompts each have their own meaning based on the color (blue, grey, yellow, or red. The blue prompt (Figure 1) means that a built in Windows component that is signed by Microsoft is requesting administrative privileges to continue. This prompt has a multicolored shield in the upper left corner. The grey prompt (Figure 2) means a software application that is signed by a third party developer is requesting admin privileges. This prompt has a yellow shield with a black exclamation mark in the upper left corner. The yellow prompt (Figure 3) signifies that a unsigned executable is requesting administrator privileges. This prompt also had a yellow shield with black exclamation mark in the upper left corner, and looks somewhat generic. Finally, the red prompt (Figure 4) means a program that was specifically blocked by an administrator has attempted to run.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BBlue.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BBlue.png" alt=""></a></p> -<p>Figure 1</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BGrey.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BGrey.png" alt=""></a></p> -<p>Figure 2</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BYellow.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BYellow.png" alt=""></a></p> -<p>Figure 3</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BRED.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/UAC2BRED.png" alt=""></a></p> -<p>Figure 4</p> - + http://localhost:1313/posts/2012-11-15-user-account-control/ + Many people rarely pay close attention to those pesky User Account Control prompts that pop up when attempting to run a program as an administrator. When a user logs into her account, she is assigned a security token based on the level of access that she has (basic user or admin). This token is what defines what programs are allowed to do. Using this concept, the users session is incapable of making changes that would affect the entire system. - diff --git a/public/tags/windows/page/1/index.html b/public/tags/windows/page/1/index.html index 67e0fcc3..eea39e85 100644 --- a/public/tags/windows/page/1/index.html +++ b/public/tags/windows/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/windows/ - + http://localhost:1313/tags/windows/ + - + diff --git a/public/tags/windowsserver/index.html b/public/tags/windowsserver/index.html index ad22e8b5..56f4d1c0 100644 --- a/public/tags/windowsserver/index.html +++ b/public/tags/windowsserver/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: WindowsServer · GeekyRyan + - - -WindowsServer - GeekyRyan - - - - - - - - - - - + - - + + + - + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,848 +79,232 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - -
    - - - - -
    -
    - -

    Tag: WindowsServer

    - - - -
    -
    -
    -

    Deploy a New ADDS Forest on Server 2019 Core

    -
    - -
    - - -
    - Prerequisites: -Change server name and IP address Configure time settings and NTP -In this post we will be reviewing the basic installation of the Active Directory Domain Services role and setup of a new forest on Windows Server Core 2019. -To get started, login to your server with administrator privileges. You will first need to type in “powershell” in the cmd prompt to start powershell. Once you do that, type in the following command to install the Active Directory Domain Services role: -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    WSUS: Update Files Not Downloading (Content File Download Failed)

    -
    - -
    - - -
    - This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates: -You may also see this event (or similar) in the Event Log. -This problem is caused by not specifying a valid path when assigning the WSUS content drive when first installing the role. The first time you load the WSUS console after installing the role, you will be prompted to specify the path to store Windows Update files. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    WSUS: An error occurred trying to connect the WSUS server

    -
    - -
    - - -
    - Ran into this error message when configuring a new WSUS server: -Restarted the WSUS, WID, and IIS services to no avail. I even rebooted the server. The WSUS console would work for a short period of time, and then would randomly stop working. -I found that the WSUS app pool in IIS was being disabled anytime new clients connected to the server. I believe this was because the app pool was running out of usable memory. -
    - - -
    - Read more -
    - - - - - - - - - -
    - -
    -
    -
    -

    WDS Service: The Service did not respond in a timely fashion

    -
    - -
    - - -
    - This was a new one for me. Usually WDS is rock solid and it just works. -Anyway, I was getting ready to deploy some servers in my lab and found that I couldn’t get WDS to start on my deployment server. I got this error message when trying to start the service: -I then tried to start the service from the Services console and got this error message: -“This was just working yesterday”, I said to myself. -
    - - -
    - Read more -
    - - - - - - - -
    - -
    -
    -
    -

    Script to Move All Disabled AD Objects to a Specified OU

    -
    - -
    +
    + + + +
    + +
    +
    +

    + Tag: WindowsServer +

    +
    + +
    +
  • + 2020-10-31 + Deploy a New ADDS Forest on Server 2019 Core +
  • -
    -
    -
    -

    The User Profile Service service failed the logon

    -
    - -
    - +
  • + 2016-11-18 + WSUS: Update Files Not Downloading (Content File Download Failed) +
  • -
    - One of my clients had a really strange issue the other day. He has a domain admin account in his domain and was not able to login to a server that I recently built. The server was an Exchange 2013 box, and was used in Coexistence mode to migrate his company from an Exchange 2007 box. -He was getting this error message when attempting to login: -This is a classic error message that I’m sure most technicians have seen before. -
    +
  • + 2016-11-10 + WSUS: An error occurred trying to connect the WSUS server +
  • +
  • + 2016-11-10 + WDS Service: The Service did not respond in a timely fashion +
  • -
    - Read more -
    +
  • + 2016-10-06 + Script to Move All Disabled AD Objects to a Specified OU +
  • +
  • + 2015-12-30 + The User Profile Service service failed the logon +
  • +
  • + 2015-09-07 + Finding All Mailboxes with a Forwarding Address in Exchange 2003 +
  • - +
  • + 2015-09-01 + Script for Querying All AD Computers Time Source +
  • - - - - -
    - -
    -
    -
    -

    Finding All Mailboxes with a Forwarding Address in Exchange 2003

    -
    - -
    - -
    - Believe it or not, the MSP I work for still has a client who is using Exchange 2003 as their primary email service. Despite several attempts at convincing them of the power of Office 365, they refuse to migrate. Last week the CFO contacted me and requested we provide them with a report of all users who have their email forwarded to another mailbox. “Ok, no problem.” I said helpfully as the client informed me of their request (at the time I didn’t even think about them having Exchange 2003…). -
    - - -
    - Read more -
    - - - - - - -
    + -
    -
    -
    -

    Script for Querying All AD Computers Time Source

    -
    - -
    - -
    - This script will iterate through all computers in Active Directory and return the configured time server for each computer. -<# .SYNOPSIS Get time source for all computers in domain .EXAMPLE Get-TimeSource .NOTES Author: Ryan Nemeth - RyanNemeth@live.com Site: http://www.geekyryan.com .LINK http://www.geekyryan.com .DESCRIPTION This function will iterate through all computers/servers in a domain and return the time source for each. #> Write-Host -foregroundcolor Red -BackgroundColor black "This script must be run on a domain controller and requires that the AD Powershell module be installed" $module = Get-Module -ListAvailable | Select-Object -ExpandProperty Name if($module -notcontains "ActiveDirectory") { Write-Host -foregroundcolor red -backgroundcolor black "***Active Directory Powershell Module Not Found***" } else { Write-Host -foregroundcolor yellow "Found Active Directory Powershell Module. -
    + +
  • 1
  • + + -
    - Read more -
    + - + +
  • 2
  • + - - - -
    - -
    -
    -
    -

    Error When Reinstalling DirSync

    -
    -
    +
    +
    + © -
    - Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process: -I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do: -
    - - -
    - Read more -
    + 2012 - + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. +
    +
    - - - -
    -
    - - - - - - -
    -
    + - - -
    -
    -
    -

    Failed to Mount Exchange 2010 Database

    -
    - -
    + + + + - -
    - Recently, one of my users’ came to me and said he was missing two months worth of email. This was just after migrating to Exchange Online. We were using Exchange 2010 with System Center DPM for backups. -I restored the database that the users’ mailbox was on from a backup then copied it over to the Exchange server from the network share I restored it to. All was going well, until I tried to mount the darn thing. -
    - - -
    - Read more -
    - - - + - + - - -
    - - - - - + + + + - - -
    - - + - + -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/windowsserver/index.xml b/public/tags/windowsserver/index.xml index 4246e75e..96e8017d 100644 --- a/public/tags/windowsserver/index.xml +++ b/public/tags/windowsserver/index.xml @@ -2,352 +2,116 @@ WindowsServer on GeekyRyan - https://rnemeth90.github.io/tags/windowsserver/ - GeekyRyan (WindowsServer) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/windowsserver/ + Recent content in WindowsServer on GeekyRyan + Hugo + en Sat, 31 Oct 2020 01:02:00 +0000 - - - - + Deploy a New ADDS Forest on Server 2019 Core - https://rnemeth90.github.io/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ + http://localhost:1313/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ Sat, 31 Oct 2020 01:02:00 +0000 - - https://rnemeth90.github.io/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ - <p>Prerequisites:</p> -<p>Change server name and IP address -Configure time settings and NTP</p> -<p>In this post we will be reviewing the basic installation of the Active Directory Domain Services role and setup of a new forest on Windows Server Core 2019.</p> -<p>To get started, login to your server with administrator privileges. You will first need to type in “powershell” in the cmd prompt to start powershell. Once you do that, type in the following command to install the Active Directory Domain Services role:</p> -<p><a href="https://lh3.googleusercontent.com/-LnSTbXjG2Hc/X5y3R3F-eWI/AAAAAAAAx2A/lWQBpA44Dmo-Jpbck2iPmgibU6z0DM1YwCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-12.png" alt=""></a></p> -<p>After installing the role, we’ll continue by creating a new ADDS Forest and promoting this server to the primary domain controller.</p> -<p>First, we’ll need to gather a password. This password will not be used for a domain user account. The local administrator on this server will become the domain administrator account for the domain. The password we’re gathering in the next step will be used for Directory Services Restore Mode (DSRM). DSRM is a recovery mode used to recover domain controllers that won’t boot up. We technically only need a password, not a username for this account.</p> -<p>Type in the following:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$cred = Get-Credential -</span></span></code></pre></div><p>In the username field for the credentials prompt below, just type in anything you want, as the value will not be used. This prompt will store our username/password in a variable object. We can then access the password within the credential object by typing:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>$cred.password -</span></span></code></pre></div><p>We can see that this password is stored as a secure string object. Let’s continue on with the Directory Services installation.</p> -<p><a href="https://lh3.googleusercontent.com/-n-W0yvwr2Zs/X5y3X64NjZI/AAAAAAAAx2E/rx5urA7p_NMl3peX5g0J7Ax7biWwNADAgCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-13.png" alt=""></a></p> -<p><a href="https://lh3.googleusercontent.com/-0k-aZrMhyGw/X5y3ckH10pI/AAAAAAAAx2I/FS56uvXCirAaBHKwWmIRQ4xIGU_jp_GFwCLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-14.png" alt=""></a></p> -<p>Once we have our credential variable, we can install a new forest and domain controller using the command below. Let us break down what this cmd is doing:</p> -<p><a href="https://lh3.googleusercontent.com/-OF_HVfCPZIM/X5y3ijEA5YI/AAAAAAAAx2M/0vMV3CJczT8D3q5x8hzPAZVSL5DycplBACLcBGAsYHQ/image.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2020/10/image-15.png" alt=""></a></p> -<p>Install-ADDSForest: The powershell cmdlet to create a new forest and domain controller</p> -<p>-DomainName: The domain name to be used for the forest</p> -<p>-DomainNetBiosName: The domain “Short name” to be used for the forest. This is the value used when you type in a username in the domainusername format. Example “myDomainbgates”.</p> -<p>-SafeModeAdministratorPassword: The value we captured in our credential prompt above. This is used for Directory Services Restore Mode. This mode can be accessed by pressing F8 while the server is booting. It is commonly used for recovering a failed domain controller.</p> -<p>-DatabasePath: The path for the Active Directory database. It’s a best practice to put this database on its own disk.</p> -<p>-LogPath: The directory for ADDS log files</p> -<p>-DomainMode: The domain functional level. The domain functional level specifies the attributes and capabilities available to objects within the domain. The higher the level you choose, the more features will be available to you.</p> -<p>-ForestMode: The forest functional level. Similar to the domain functional level but applies to the entire forest.</p> -<p>-InstallDNS: Install the DNS role alongside the ADDS role.</p> -<p>-WhatIf: This is a powershell “thing”. Most cmdlets have the “whatif” parameter. It basically allows you to run the cmdlet in “test” mode without actually making any changes to your environment. Once you’re happy with the output, you can remove the “whatif” parameter and run the command to install ADDS and promote this server to a domain controller.</p> - + http://localhost:1313/posts/2020-10-31-deploy-new-adds-forest-on-server-2019/ + Prerequisites: Change server name and IP address Configure time settings and NTP In this post we will be reviewing the basic installation of the Active Directory Domain Services role and setup of a new forest on Windows Server Core 2019. To get started, login to your server with administrator privileges. You will first need to type in “powershell” in the cmd prompt to start powershell. Once you do that, type in the following command to install the Active Directory Domain Services role: - WSUS: Update Files Not Downloading (Content File Download Failed) - https://rnemeth90.github.io/posts/2016-11-18-wsus-update-files-not-downloading/ + http://localhost:1313/posts/2016-11-18-wsus-update-files-not-downloading/ Fri, 18 Nov 2016 15:13:00 +0000 - - https://rnemeth90.github.io/posts/2016-11-18-wsus-update-files-not-downloading/ - <p>This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-18_10h02_21.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-18_10h02_21.png" alt=""></a></p> -<p>You may also see this event (or similar) in the Event Log.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_32.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_32.png" alt=""></a></p> -<p>This problem is caused by not specifying a valid path when assigning the WSUS content drive when first installing the role. The first time you load the WSUS console after installing the role, you will be prompted to specify the path to store Windows Update files. WSUS does not like to have its content directory be the root of a partition. For example, if I were to specify “e:” as the path for the Windows Update content, the wizard would give you an error message stating that the path is not valid. However, it doesn’t prompt you to re-enter the path if you click close. The WSUS console opens immediately after and that invalid path is where WSUS will try to store your update files. This is and has been a known bug for a while and needs to be addressed by Microsoft. Evidence of the invalid path can be found in the registry under:</p> -<p>HKLMSoftwareMicrosoftUpdate ServicesServerSetupContentDir</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_44.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_44.png" alt=""></a></p> -<p>If you come across this problem, you can change the ContentDir above to a valid path. Keep in mind that it cannot be the root of a partition. You need to specify a drive letter with a subfolder (eg: e:wsus).</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h54_54.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h54_54.png" alt=""></a></p> -<p>The other option is to reinstall the WSUS role. If you remove the role, the WID database is not removed, unless you remove that role as well (or manually delete the database). This means that when you reinstall the WSUS role, it will be able to use that same database and any clients that have contacted the WSUS server will immediately show up in the console. The same is true for update metadata. The new WSUS installation will still have the same approvals, denials, etc. as the old installation.</p> -<p>Regardless of what option you choose, I suggest rebooting the server after you make the changes.</p> - + http://localhost:1313/posts/2016-11-18-wsus-update-files-not-downloading/ + This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates: You may also see this event (or similar) in the Event Log. This problem is caused by not specifying a valid path when assigning the WSUS content drive when first installing the role. The first time you load the WSUS console after installing the role, you will be prompted to specify the path to store Windows Update files. - WSUS: An error occurred trying to connect the WSUS server - https://rnemeth90.github.io/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ + http://localhost:1313/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ Thu, 10 Nov 2016 15:18:00 +0000 - - https://rnemeth90.github.io/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ - <p>Ran into this error message when configuring a new WSUS server:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h56_00.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h56_00.png" alt=""></a></p> -<p>Restarted the WSUS, WID, and IIS services to no avail. I even rebooted the server. The WSUS console would work for a short period of time, and then would randomly stop working.</p> -<p>I found that the WSUS app pool in IIS was being disabled anytime new clients connected to the server. I believe this was because the app pool was running out of usable memory.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h28_56.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h28_56.png" alt=""></a></p> -<p>You can manually start the app pool in IIS, but it will continue to crash.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h56_48.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h56_48.png" alt=""></a></p> -<p>The solution for me was to increase the memory limit available for the application pool:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h57_38.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h57_38.png" alt=""></a></p> -<p>By default it is only configured to use just under 2 GBs. I reconfigured it to use up to 4 GB and the WSUS console has not crashed since. After re-configuring the memory for the application pool, run an IIS reset or reboot the server.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h31_40.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h31_40.png" alt=""></a></p> -<p>UPDATE: Setting the Private Memory Limit to “0” will allow the application pool to use whatever amount of memory it needs.</p> - + http://localhost:1313/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ + Ran into this error message when configuring a new WSUS server: Restarted the WSUS, WID, and IIS services to no avail. I even rebooted the server. The WSUS console would work for a short period of time, and then would randomly stop working. I found that the WSUS app pool in IIS was being disabled anytime new clients connected to the server. I believe this was because the app pool was running out of usable memory. - WDS Service: The Service did not respond in a timely fashion - https://rnemeth90.github.io/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ + http://localhost:1313/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ Thu, 10 Nov 2016 02:19:00 +0000 - - https://rnemeth90.github.io/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ - <p>This was a new one for me. Usually WDS is rock solid and it just works.</p> -<p>Anyway, I was getting ready to deploy some servers in my lab and found that I couldn’t get WDS to start on my deployment server. I got this error message when trying to start the service:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h02_29.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h02_29.png" alt=""></a></p> -<p>I then tried to start the service from the Services console and got this error message:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h02_42.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h02_42.png" alt=""></a></p> -<p>“This was just working yesterday”, I said to myself. What could possibly have happened since yesterday evening that could cause this? I looked in the event log and after scrolling through the Administrative Events, I found this:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h04_33.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h04_33.png" alt=""></a></p> -<p>The solution was so obvious it was staring me in the face, but I wanted to verify first. So I fired up a cmd prompt and ran netstat, and found this:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h06_14.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h06_14.png" alt=""></a></p> -<p>I had installed DHCP on this server the night before and totally forgot about it. Anyway, the solution was simple. I just needed to tell the WDS service to not listen on port 67. To do that, just open the WDS server properties and got to the “DHCP” tab. Then check the box next to “Do not listen on DHCP Ports”.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h08_04.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h08_04.png" alt=""></a></p> -<p>I was then able to start the DHCP service.</p> - + http://localhost:1313/posts/2016-11-10-wds-service-the-service-did-not-respond-in-a-timely-fashion/ + This was a new one for me. Usually WDS is rock solid and it just works. Anyway, I was getting ready to deploy some servers in my lab and found that I couldn’t get WDS to start on my deployment server. I got this error message when trying to start the service: I then tried to start the service from the Services console and got this error message: “This was just working yesterday”, I said to myself. - Script to Move All Disabled AD Objects to a Specified OU - https://rnemeth90.github.io/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ + http://localhost:1313/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ Thu, 06 Oct 2016 03:03:00 +0000 - - https://rnemeth90.github.io/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ - <p>The title says it all. This script will move all disabled AD objects to a specified OU. This script accepts parameters that will allow you to specify whether you want to move Users or Computers and the destination OU. It also accepts a “test mode” parameter that will run the script and output the results, without actually modifying Active Directory.</p> -<p>This is revision 1 of the script. There are still several improvements I would like to make, including better error handling and recovery.</p> -<p>If you have any suggestions or requests, please leave a comment.</p> -<p><a href="https://drive.google.com/open?id=0B2K6VOnt6zeXMVFleWZISHZBTnc">Download Here</a></p> - + http://localhost:1313/posts/2016-10-06-script-to-move-all-disabled-ad-objects-to-a-specified-ou/ + The title says it all. This script will move all disabled AD objects to a specified OU. This script accepts parameters that will allow you to specify whether you want to move Users or Computers and the destination OU. It also accepts a “test mode” parameter that will run the script and output the results, without actually modifying Active Directory. This is revision 1 of the script. There are still several improvements I would like to make, including better error handling and recovery. - The User Profile Service service failed the logon - https://rnemeth90.github.io/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ + http://localhost:1313/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ Wed, 30 Dec 2015 10:38:00 +0000 - - https://rnemeth90.github.io/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ - <p>One of my clients had a really strange issue the other day. He has a domain admin account in his domain and was not able to login to a server that I recently built. The server was an Exchange 2013 box, and was used in Coexistence mode to migrate his company from an Exchange 2007 box.</p> -<p>He was getting this error message when attempting to login:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/12/2015-12-30_09h38_53.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/12/2015-12-30_09h38_53.png" alt=""></a></p> -<p>This is a classic error message that I’m sure most technicians have seen before. Usually the resolution is to go into the registry and rename the user profile key to have a “.bak” extension and then do some other magic. However, this time, that was not the case. I looked in the registry and didn’t even see a reg key for his profile. I then looked in the c:users folder and didn’t see a folder for his profile. Strange…</p> -<p>So what exactly was happening? Well, I took a look at the Event Viewer and found this error message:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/12/2015-12-30_09h34_06.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/12/2015-12-30_09h34_06.png" alt=""></a></p> -<p>I browsed to the file referenced in the error message and deleted it. Walla! He was able to login with his admin account. I’m not sure why this file was in the default user profile. It has something to do with Customer Experience Improvement Program:</p> -<p><a href="http://www.nextofwindows.com/what-is-sqmdata-and-sqm-file-in-windows-7-and-how-to-delete-them">http://www.nextofwindows.com/what-is-sqmdata-and-sqm-file-in-windows-7-and-how-to-delete-them</a></p> - + http://localhost:1313/posts/2015-12-30-the-user-profile-service-service-failed-the-logon/ + One of my clients had a really strange issue the other day. He has a domain admin account in his domain and was not able to login to a server that I recently built. The server was an Exchange 2013 box, and was used in Coexistence mode to migrate his company from an Exchange 2007 box. He was getting this error message when attempting to login: This is a classic error message that I’m sure most technicians have seen before. - Finding All Mailboxes with a Forwarding Address in Exchange 2003 - https://rnemeth90.github.io/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ + http://localhost:1313/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ Mon, 07 Sep 2015 23:13:00 +0000 - - https://rnemeth90.github.io/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ - <p>Believe it or not, the MSP I work for still has a client who is using Exchange 2003 as their primary email service. Despite several attempts at convincing them of the power of Office 365, they refuse to migrate. Last week the CFO contacted me and requested we provide them with a report of all users who have their email forwarded to another mailbox. “Ok, no problem.” I said helpfully as the client informed me of their request (at the time I didn’t even think about them having Exchange 2003…). I figured I would just connect to their server and do some quick PowerShell magic, and that would be it. Quick and painless, right? Wrong.</p> -<p>I did the RDP dance and got connected to their server, and my jaw just about hit the floor when I couldn’t find the Exchange Management Shell! I asked around the office to see if any of the other guys could help, but no one knew what to do. However, after talking with one of the guys, I remembered that this is Active Directory we are dealing with. There are objects, and those objects have attributes. The mailboxes/user accounts are objects, and those objects have attributes. So what attribute is it that controls forwarding addresses? I manually found one of the users who had a forwarding address configured. Then I opened up Active Directory Users and Computers, opened up her account properties, and went to the Attribute Editor tab. I filtered for attributes that have values and was able to see the email address that her mail was forwarding to. This was the “altRecipient” attribute.</p> -<p>I then did an “Advanced” search in Active Directory Users and Computers for any objects that have the “altRecipient” attribute configured, like so:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/09/ExchangeForwarding.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/09/ExchangeForwarding.png" alt=""></a></p> -<p>This search showed me all of the mailboxes that have an alternate recipient (forwarding address) configured. Not sure if there is another way to obtain this information, but this is the way that worked for me. Hopefully this article is able to help someone in the same situation.</p> - + http://localhost:1313/posts/2015-09-07-finding-all-mailboxes-with-a-forwarding-address-in-exchange-2003/ + Believe it or not, the MSP I work for still has a client who is using Exchange 2003 as their primary email service. Despite several attempts at convincing them of the power of Office 365, they refuse to migrate. Last week the CFO contacted me and requested we provide them with a report of all users who have their email forwarded to another mailbox. “Ok, no problem.” I said helpfully as the client informed me of their request (at the time I didn’t even think about them having Exchange 2003…). - Script for Querying All AD Computers Time Source - https://rnemeth90.github.io/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ + http://localhost:1313/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ Tue, 01 Sep 2015 21:05:00 +0000 - - https://rnemeth90.github.io/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ - <p>This script will iterate through all computers in Active Directory and return the configured time server for each computer.</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span><span style="color:#75715e">&lt;# -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">SYNOPSIS</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Get time source for all computers in domain -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">EXAMPLE</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Get-TimeSource -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">NOTES</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Author: Ryan Nemeth - RyanNemeth@live.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> Site: http://www.geekyryan.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">LINK</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> http://www.geekyryan.com -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> .</span><span style="color:#e6db74">DESCRIPTION</span><span style="color:#75715e"> -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> This function will iterate through all computers/servers in a domain and return the time source -</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> for each. -</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#&gt;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Write-Host -foregroundcolor Red -BackgroundColor black <span style="color:#e6db74">&#34;This script must be run on a domain controller and requires that the AD Powershell module be installed&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$module = Get-Module -ListAvailable | Select-Object -ExpandProperty Name -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span>($module <span style="color:#f92672">-notcontains</span> <span style="color:#e6db74">&#34;ActiveDirectory&#34;</span>) { -</span></span><span style="display:flex;"><span> Write-Host -foregroundcolor red -backgroundcolor black <span style="color:#e6db74">&#34;***Active Directory Powershell Module Not Found***&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span> { -</span></span><span style="display:flex;"><span> Write-Host -foregroundcolor yellow <span style="color:#e6db74">&#34;Found Active Directory Powershell Module. Importing...&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Import-Module ActiveDirectory -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$computers = get-adcomputer -filter * | Select-Object -ExpandProperty Name -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span>($computer <span style="color:#66d9ef">in</span> $computers) { -</span></span><span style="display:flex;"><span> $tm_source = w32tm /query /computer<span style="color:#960050;background-color:#1e0010">:</span>$computer /source -</span></span><span style="display:flex;"><span> write-host <span style="color:#e6db74">&#34;The time source for&#34;</span> $computer <span style="color:#e6db74">&#34;is&#34;</span> $tm_source -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><img src="https://github.com/rnemeth90/PowerShell/blob/master/NTP/Get-TimeSource.ps1" alt=""></p> - + http://localhost:1313/posts/2015-09-01-script-for-querying-all-ad-computers-time-source/ + This script will iterate through all computers in Active Directory and return the configured time server for each computer. &lt;# .SYNOPSIS Get time source for all computers in domain .EXAMPLE Get-TimeSource .NOTES Author: Ryan Nemeth - RyanNemeth@live.com Site: http://www.geekyryan.com .LINK http://www.geekyryan.com .DESCRIPTION This function will iterate through all computers/servers in a domain and return the time source for each. #&gt; Write-Host -foregroundcolor Red -BackgroundColor black &#34;This script must be run on a domain controller and requires that the AD Powershell module be installed&#34; $module = Get-Module -ListAvailable | Select-Object -ExpandProperty Name if($module -notcontains &#34;ActiveDirectory&#34;) { Write-Host -foregroundcolor red -backgroundcolor black &#34;***Active Directory Powershell Module Not Found***&#34; } else { Write-Host -foregroundcolor yellow &#34;Found Active Directory Powershell Module. - Error When Reinstalling DirSync - https://rnemeth90.github.io/posts/2015-08-13-error-when-reinstalling-dirsync/ + http://localhost:1313/posts/2015-08-13-error-when-reinstalling-dirsync/ Thu, 13 Aug 2015 18:59:00 +0000 - - https://rnemeth90.github.io/posts/2015-08-13-error-when-reinstalling-dirsync/ - <p>Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process:</p> -<p><a href="https://geekyryan.com/wp-content/uploads/2015/08/1.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/1.png" alt=""></a></p> -<p>I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do:</p> -<ul> -<li>Uninstall Windows Azure Active Directory Sync tool and reboot -<a href="https://geekyryan.com/wp-content/uploads/2015/08/2.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/2.png" alt=""></a></li> -</ul> -<p>Remove this directory and all subfolders: C:Program FilesWindows Azure Active Directory Sync -<a href="https://geekyryan.com/wp-content/uploads/2015/08/3.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/3.png" alt=""></a></p> -<p>If you created a domain account to use for DirSync, remove it. Also remove the Office 365 account you created.</p> -<ul> -<li>Delete the Group accounts that the DirSync wizard created. Their names all begin with “FIM”</li> -</ul> -<p><a href="https://geekyryan.com/wp-content/uploads/2015/08/4.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/4.png" alt=""></a></p> -<p>Uninstall MSSQL:</p> -<ul> -<li>Delete the MSSQL directory: C:Program FilesMicrosoft SQL Server</li> -<li>Reboot!</li> -<li>You should be able to install and configure DirSync now.</li> -</ul> -<p><a href="https://geekyryan.com/wp-content/uploads/2015/08/5.png"><img src="https://geekyryan.com/wp-content/uploads/2015/08/5.png" alt=""></a></p> - + http://localhost:1313/posts/2015-08-13-error-when-reinstalling-dirsync/ + Today is just not my day! After a failed attempt at installing/configuring DirSync, I removed it and tried to install and configure it again. This time did not prove any more successful. I was getting this error midway through the install process: I was able to figure this out after a little while and wanted to sure what I learned. If you are seeing this error message after removing DirSync and trying to reinstall, here’s what you need to do: - Failed to Mount Exchange 2010 Database - https://rnemeth90.github.io/posts/2015-08-12-failed-to-mount-exchange-2010-database/ + http://localhost:1313/posts/2015-08-12-failed-to-mount-exchange-2010-database/ Wed, 12 Aug 2015 12:59:00 +0000 - - https://rnemeth90.github.io/posts/2015-08-12-failed-to-mount-exchange-2010-database/ - <p>Recently, one of my users’ came to me and said he was missing two months worth of email. This was just after migrating to Exchange Online. We were using Exchange 2010 with System Center DPM for backups.</p> -<p>I restored the database that the users’ mailbox was on from a backup then copied it over to the Exchange server from the network share I restored it to. All was going well, until I tried to mount the darn thing.</p> -<p>I was getting this error and could not for the life of me decry-pt the meaning of it. There is obviously some type of IO issue/file not found. But what could it be?</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/1-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/1-1.png" alt=""></a></p> -<p>I figured I’d better kick this one off with some basic troubleshooting. First, I checked the health of the database and made sure it was clean. Passed that test…</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/2-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/2-1.png" alt=""></a></p> -<p>Then ran a repair on the database, to no avail.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/3-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/3-1.png" alt=""></a></p> -<p>After racking my brain for a good thirty minutes, and a few failed Google searches, I found the solution. It was so simple! I created the log file directory in the folder with the database, and voila, the database mounted without a single error!</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/7.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/7.png" alt=""></a></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/4-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/4-1.png" alt=""></a><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/5-1.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/5-1.png" alt=""></a></p> -<p>I was able to see the ‘supposed’ location of the log file by opening the Exchange Management Shell and running the ‘Get-MailboxDatabase’ cmdlet, like so:</p> -<p><em>Get-MailBoxDatabase –Identity <Recovery DB Name> | FL Name, ServerName, EDBFilePath, LogFolderPath</em></p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2015/08/6.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2015/08/6.png" alt=""></a></p> -<p>I’m not sure why the database mounting process isn’t capable of creating the log file directory… I think Microsoft would have thought and planned for a situation like this. Hope this helps!</p> - + http://localhost:1313/posts/2015-08-12-failed-to-mount-exchange-2010-database/ + Recently, one of my users’ came to me and said he was missing two months worth of email. This was just after migrating to Exchange Online. We were using Exchange 2010 with System Center DPM for backups. I restored the database that the users’ mailbox was on from a backup then copied it over to the Exchange server from the network share I restored it to. All was going well, until I tried to mount the darn thing. - Powershell: SID to Username - https://rnemeth90.github.io/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ + http://localhost:1313/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ Mon, 08 Dec 2014 13:43:00 +0000 - - https://rnemeth90.github.io/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ - <p>This is a simple script to convert a SID to a username</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span><span style="color:#75715e"># Returns a username based on a SID</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Author: Ryan Nemeth</span> -</span></span><span style="display:flex;"><span><span style="color:#75715e"># Date: 12/2/2014</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>$SID = read-host <span style="color:#960050;background-color:#1e0010">“</span>Please enter the SID<span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#960050;background-color:#1e0010">”</span> -</span></span><span style="display:flex;"><span>$object = New-Object System.Security.Principal.SecurityIdentifier($SID) -</span></span><span style="display:flex;"><span>$User = $object.Translate( \[System.Security.Principal.NTAccount\]) -</span></span><span style="display:flex;"><span>write-host <span style="color:#960050;background-color:#1e0010">“</span>The user is<span style="color:#960050;background-color:#1e0010">:</span> <span style="color:#960050;background-color:#1e0010">”</span> $User.Value -</span></span></code></pre></div> + http://localhost:1313/posts/2014-12-08-powershell-sid-to-username-powershell-sid-to-username/ + This is a simple script to convert a SID to a username # Returns a username based on a SID # Author: Ryan Nemeth # Date: 12/2/2014 $SID = read-host “Please enter the SID: ” $object = New-Object System.Security.Principal.SecurityIdentifier($SID) $User = $object.Translate( \[System.Security.Principal.NTAccount\]) write-host “The user is: ” $User.Value - Unlock a Domain User from CMD Line - https://rnemeth90.github.io/posts/2014-12-08-unlock-domain-user-from-cmd-line/ + http://localhost:1313/posts/2014-12-08-unlock-domain-user-from-cmd-line/ Mon, 08 Dec 2014 02:11:00 +0000 - - https://rnemeth90.github.io/posts/2014-12-08-unlock-domain-user-from-cmd-line/ - <p>To unlock a domain user from the command line, use this command:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>net user &amp;lt;username&amp;gt; /domain /active:yes -</span></span></code></pre></div><p>This can also be done using Powershell:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Powershell" data-lang="Powershell"><span style="display:flex;"><span>Unlock-ADAccount -identity <span style="color:#960050;background-color:#1e0010">“</span>CN=John,OU=myUsers,DC=myDomain,DC=local<span style="color:#960050;background-color:#1e0010">”</span> -</span></span></code></pre></div> + http://localhost:1313/posts/2014-12-08-unlock-domain-user-from-cmd-line/ + To unlock a domain user from the command line, use this command: net user &amp;lt;username&amp;gt; /domain /active:yes This can also be done using Powershell: Unlock-ADAccount -identity “CN=John,OU=myUsers,DC=myDomain,DC=local” - The Case of Transitive Trusts and Dropped RPC Connections - https://rnemeth90.github.io/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ + http://localhost:1313/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ Tue, 25 Nov 2014 01:27:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ - <p>I was at a client earlier this morning, working to get a transitive forest trust setup between their two domains. Setting up the trust on ServerA to DomainB went without issue. However, when trying to create the trust between ServerB and DomainA, I received this error: The secure channel reset on Active Directory Domain Controller (Your domain controller) of domain (Your domain) to domain (your other domain) failed with error: RPC server is unavailable.</p> -<p>Troubleshooting (as always) started off with the basics: is the firewall on or off, are the services running, are the names being properly resolved, etc. Well, the Windows Firewall on both servers was off and -the RPC services were running. So what now?? I fired up NMAP on ServerB and did a syn scan on ServerA. After reviewing the output, I could see that the ports were open. I then went over to ServerA and opened up the Services MSC console. The RPC services appeared to be running. Being that they are system services and you cannot manually interact with them, I was unable to manually restart them. Just out of curiosity,</p> -<p>I opened a command prompt while connected to that server and ran Netstat -A. This is when I had the “AHA!” moment. Nothing was listening on any of the RPC ports! I rebooted the server (something I don’t really like to do..), logged in and ran Netstat -A again. This time, RPC was listening. I went back over to ServerB, walked through the New Trust Wizard, and success! Oh, the feeling of victory!</p> - + http://localhost:1313/posts/2014-11-25-the-case-of-transitive-trusts-and-dropped-rpc-connections/ + I was at a client earlier this morning, working to get a transitive forest trust setup between their two domains. Setting up the trust on ServerA to DomainB went without issue. However, when trying to create the trust between ServerB and DomainA, I received this error: The secure channel reset on Active Directory Domain Controller (Your domain controller) of domain (Your domain) to domain (your other domain) failed with error: RPC server is unavailable. - Creating Applocker Policies - https://rnemeth90.github.io/posts/2014-11-17-creating-applocker-policies/ + http://localhost:1313/posts/2014-11-17-creating-applocker-policies/ Mon, 17 Nov 2014 01:40:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-17-creating-applocker-policies/ - <p>Application Control Policies can be used to restrict what programs a user is allowed to run. They can be created at the local Group Policy level or the Domain GPO level. There are 4 different types of Applocker RULES that you can implement, depending on what type of executable you want to control access to.</p> -<p>Executable Rules – EXE’s, COM’s, etc.</p> -<p>Script Rules – batch files, VB scripts, etc.</p> -<p>AppX Rules – AppX Packages (Windows 8.1/Server 2012 R2 Metro Interface programs)</p> -<p>Windows Installer Rules – Windows Installer Packages and MSU Packages</p> -<p>After choosing what type of executable file you want to control, you can choose the corresponding rule type. Then, you will be able to choose the criteria for that rule type. Applocker rule criteria are things such as file path, publisher, and file hash. Criteria allow you to be more granular with your selections. Rather than saying you want to block access to ALL executable’s on a computer, you can choose to block access to executable’s published by a certain vendor, or found in a specified directory.</p> -<p>Applocker can be found in the Group Policy Editor at: Computer Configuration\Windows Settings\Security Settings. Application Control Policies. By right-clicking on the Applocker node, you can configure rule enforcement. You have the option to enforce rules or audit rules based on rule type. Auditing will allow</p> -<p>you get a good grasp on what Applocker will do in your environment if you are unsure.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h18_31.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h18_31.png" alt=""></a></p> -<p>Clicking the Advanced tab of this window will allow you to configure rule enforcement for Dynamic Link Libraries. It’s best to leave DLL rule enforcement disabled, because it can cause a system to suffer dramatic performance hits.</p> -<p>Underneath the Applocker node, you will find nodes for the 4 different rule types. You can create new rules by right clicking on any of these nodes and clicking “Create New Rule”. Before creating any rules, I advise you to create the default rules. Doing this will ensure that users are still able to run programs in the Program Files directory and the Windows directory. Also, members of the built-in Administrators group will be allowed to run ANY files.</p> -<p>When creating custom Applocker rules, you can choose to allow or deny the program, and what group the rule will apply to (by default, the “Everyone” special identity is always selected).</p> -<p>You will also be able to choose the criteria for the executable that you are controlling.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h26_30.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h26_30.png" alt=""></a></p> -<p>If the executable has a digital signature from the software publisher, choose “Publisher”. Doing so will give you even more options:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h28_47.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2014/11/2014-11-16_20h28_47.png" alt=""></a></p> -<p>This allows you to really drill down and get granular with the rule. Microsoft allows us to control access to the file based on the Publisher, the Product Name, the File Name, and even the File Version.</p> -<p>Creating rules based on File Path criteria is not advised, being that if the file jumps directories, the rule will no longer apply. I also don’t advise using the File Hash criteria. My reason behind this is, if the file gets updated, the hash changes. If that happens, the rule is no longer valid.</p> -<p>After choosing the criteria type you would like to use, you can choose to create exceptions, if any. When multiple rules conflict, the order of precedence is Publisher, File Hash, and then File Path. So Publisher rules will always override File Hash rules, File Hash rules will always override File Path rules, and you get the point…</p> -<p>Finally, in order for your endpoint workstations to process Applocker rules, the Application Identity Service must be running. I like to control this with the same GPO that I configure Applocker in.</p> - + http://localhost:1313/posts/2014-11-17-creating-applocker-policies/ + Application Control Policies can be used to restrict what programs a user is allowed to run. They can be created at the local Group Policy level or the Domain GPO level. There are 4 different types of Applocker RULES that you can implement, depending on what type of executable you want to control access to. Executable Rules – EXE’s, COM’s, etc. Script Rules – batch files, VB scripts, etc. AppX Rules – AppX Packages (Windows 8. - BranchCache - https://rnemeth90.github.io/posts/2014-11-16-branchcache/ + http://localhost:1313/posts/2014-11-16-branchcache/ Sun, 16 Nov 2014 21:16:00 +0000 - - https://rnemeth90.github.io/posts/2014-11-16-branchcache/ - <p>Branchcache is a technology unique to Windows 7 and Windows Server 2008 R2. It provides faster connection to shared files across wide area networks. Branchcache works by caching content hosted on remote servers on a local caching server in the LAN. When a client queries for data on a remote server, it first looks in the local caching server. If the data is not found there, the remote server is accessed and transfer’s the data to the local caching server, where it is then accessed by the client who originally made the request. That way, all future client requests will not have to go across the wide area network, rather opting to access the local caching server until the data changes.</p> -<p>Branchcache is only available on Windows 7 clients running Enterprise or Ultimate, and Windows Server 2008 R2. Branchcache becomes active when the round trip latency time from client to remote server exceeds 80 milliseconds.</p> -<p>Branchcache is available in two modes: distributed cache mode and hosted cache mode. What you just read above was the basics of hosted cached mode. Distributed cache mode works differently to achieve the same results. When a client accesses data across the WAN, it stores that data in its own cache. This way, if another client needs access to the data, it can retrieve it locally. Also, this allows each client to host part of the cache, rather than one machine hosting the entire cache.</p> -<p>There are two steps to configuring Branchcache on a Windows 7 client. I will not include the server configuration at this point in time.</p> -<p>Enable Branchcache (Hosted or Distributed, Server 08 R2 will be required for Hosted mode)</p> -<p>Configure the appropriate ports within the Windows Firewall</p> -<p>You can enable Branchcache from within Group Policy or by using the Netsh command. When using Group Policy, navigate to Computer Configuration &gt; Administrative Templates &gt; Network &gt; Branchcache. From here you can turn on Branchcache and enable the mode you want to use. You can also set the percentage of disk space to be used for caching. After this, open the Windows Firewall and unblock the Branchcache ports. You only need to do this when configuring Branchcache via Group Policy. Using the Netsh command automatically configures the firewall. Here are the basic commands for Netsh:</p> -<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>Netsh Branchcache set service mode<span style="color:#f92672">=</span>distributed -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Netsh Branchcache reset -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Netsh Branchcache show status -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>Netsh Branchcache set cachesize -</span></span></code></pre></div><p>*Configuring Branchcache must be done from an administrative command prompt.</p> - + http://localhost:1313/posts/2014-11-16-branchcache/ + Branchcache is a technology unique to Windows 7 and Windows Server 2008 R2. It provides faster connection to shared files across wide area networks. Branchcache works by caching content hosted on remote servers on a local caching server in the LAN. When a client queries for data on a remote server, it first looks in the local caching server. If the data is not found there, the remote server is accessed and transfer’s the data to the local caching server, where it is then accessed by the client who originally made the request. - diff --git a/public/tags/windowsserver/page/1/index.html b/public/tags/windowsserver/page/1/index.html index 3d6db409..5301424d 100644 --- a/public/tags/windowsserver/page/1/index.html +++ b/public/tags/windowsserver/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/windowsserver/ - + http://localhost:1313/tags/windowsserver/ + - + diff --git a/public/tags/windowsserver/page/2/index.html b/public/tags/windowsserver/page/2/index.html index f59194f4..84090aa7 100644 --- a/public/tags/windowsserver/page/2/index.html +++ b/public/tags/windowsserver/page/2/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: WindowsServer · GeekyRyan + - - -WindowsServer - GeekyRyan - - - - + - - - + + + - - - - - - + + + + + + + + + - - - - - - - - - + + + + - + + + - + - - - - - - - - - - + + + - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,525 +79,207 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    - + + + - - - - - - - -
    -
    - -

    Tag: WindowsServer

    - - - -
    -
    -
    -

    Powershell: SID to Username

    -
    - -
    - - -
    - This is a simple script to convert a SID to a username -# Returns a username based on a SID # Author: Ryan Nemeth # Date: 12/2/2014 $SID = read-host “Please enter the SID: ” $object = New-Object System.Security.Principal.SecurityIdentifier($SID) $User = $object.Translate( \[System.Security.Principal.NTAccount\]) write-host “The user is: ” $User.Value -
    - +
    + + + + -
    - -
    -
    -
    -

    Unlock a Domain User from CMD Line

    -
    - -
    +
    + + + -
    -
    -
    -

    The Case of Transitive Trusts and Dropped RPC Connections

    -
    - -
    - -
    - I was at a client earlier this morning, working to get a transitive forest trust setup between their two domains. Setting up the trust on ServerA to DomainB went without issue. However, when trying to create the trust between ServerB and DomainA, I received this error: The secure channel reset on Active Directory Domain Controller (Your domain controller) of domain (Your domain) to domain (your other domain) failed with error: RPC server is unavailable. -
    + -
    - Read more -
    + +
  • 1
  • + + - + - - - -
    - -
    -
    -
    -

    Creating Applocker Policies

    -
    -
    +
    +
    + © -
    - Application Control Policies can be used to restrict what programs a user is allowed to run. They can be created at the local Group Policy level or the Domain GPO level. There are 4 different types of Applocker RULES that you can implement, depending on what type of executable you want to control access to. -Executable Rules – EXE’s, COM’s, etc. -Script Rules – batch files, VB scripts, etc. -AppX Rules – AppX Packages (Windows 8. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - - -
    +
    +
    -
    - - - - - - -
    -
    - - - -
    -
    -
    -

    BranchCache

    -
    - -
    + - -
    - Branchcache is a technology unique to Windows 7 and Windows Server 2008 R2. It provides faster connection to shared files across wide area networks. Branchcache works by caching content hosted on remote servers on a local caching server in the LAN. When a client queries for data on a remote server, it first looks in the local caching server. If the data is not found there, the remote server is accessed and transfer’s the data to the local caching server, where it is then accessed by the client who originally made the request. -
    - - -
    - Read more -
    - - - + + + + - + + - -
    - - - - - + + + + - - -
    - - + - + -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/wsus/index.html b/public/tags/wsus/index.html index 43ab2f83..7b416ab6 100644 --- a/public/tags/wsus/index.html +++ b/public/tags/wsus/index.html @@ -1,113 +1,77 @@ + - - - - - - - + + Tag: WSUS · GeekyRyan + - - -WSUS - GeekyRyan - - - - - - - - - - + - - + + + - - + + + + + + + + + - - - - - - - - + + + + - - - + + + - - - - - + - + + + - - - - - - - - - - + + + + + - - - - - - - - - + + + @@ -115,347 +79,161 @@ - - - Skip to main content -
    -
    - -
    -

    - GeekyRyan -

    -
    -
    - -

    Tag: WSUS

    - + 2016-11-18 + WSUS: Update Files Not Downloading (Content File Download Failed) + +
  • + 2016-11-10 + WSUS: An error occurred trying to connect the WSUS server +
  • -
    -
    -
    -

    WSUS: Update Files Not Downloading (Content File Download Failed)

    -
    - -
    + + - -
    - This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates: -You may also see this event (or similar) in the Event Log. -This problem is caused by not specifying a valid path when assigning the WSUS content drive when first installing the role. The first time you load the WSUS console after installing the role, you will be prompted to specify the path to store Windows Update files. -
    - - -
    - Read more -
    - - - - - -
    - -
    -
    -
    -

    WSUS: An error occurred trying to connect the WSUS server

    -
    -
    +
    +
    + © -
    - Ran into this error message when configuring a new WSUS server: -Restarted the WSUS, WID, and IIS services to no avail. I even rebooted the server. The WSUS console would work for a short period of time, and then would randomly stop working. -I found that the WSUS app pool in IIS was being disabled anytime new clients connected to the server. I believe this was because the app pool was running out of usable memory. -
    - + 2012 - -
    - Read more -
    + 2024 + Ryan Nemeth + · + Powered by Hugo & Coder. - - - - +
    +
    -
    - https://rnemeth90.github.io/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ - Ryan + + + + + -
    - - - - - - -
    -
    + - - - + + + - - -
    - - - -

    + - Ryan Nemeth + - - / - - + - - - -

    -
    + - - + + diff --git a/public/tags/wsus/index.xml b/public/tags/wsus/index.xml index 8775cac0..3ca7d8e9 100644 --- a/public/tags/wsus/index.xml +++ b/public/tags/wsus/index.xml @@ -2,55 +2,25 @@ WSUS on GeekyRyan - https://rnemeth90.github.io/tags/wsus/ - GeekyRyan (WSUS) - Hugo -- gohugo.io - en-us + http://localhost:1313/tags/wsus/ + Recent content in WSUS on GeekyRyan + Hugo + en Fri, 18 Nov 2016 15:13:00 +0000 - - - - + WSUS: Update Files Not Downloading (Content File Download Failed) - https://rnemeth90.github.io/posts/2016-11-18-wsus-update-files-not-downloading/ + http://localhost:1313/posts/2016-11-18-wsus-update-files-not-downloading/ Fri, 18 Nov 2016 15:13:00 +0000 - - https://rnemeth90.github.io/posts/2016-11-18-wsus-update-files-not-downloading/ - <p>This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-18_10h02_21.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-18_10h02_21.png" alt=""></a></p> -<p>You may also see this event (or similar) in the Event Log.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_32.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_32.png" alt=""></a></p> -<p>This problem is caused by not specifying a valid path when assigning the WSUS content drive when first installing the role. The first time you load the WSUS console after installing the role, you will be prompted to specify the path to store Windows Update files. WSUS does not like to have its content directory be the root of a partition. For example, if I were to specify “e:” as the path for the Windows Update content, the wizard would give you an error message stating that the path is not valid. However, it doesn’t prompt you to re-enter the path if you click close. The WSUS console opens immediately after and that invalid path is where WSUS will try to store your update files. This is and has been a known bug for a while and needs to be addressed by Microsoft. Evidence of the invalid path can be found in the registry under:</p> -<p>HKLMSoftwareMicrosoftUpdate ServicesServerSetupContentDir</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_44.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-15_16h39_44.png" alt=""></a></p> -<p>If you come across this problem, you can change the ContentDir above to a valid path. Keep in mind that it cannot be the root of a partition. You need to specify a drive letter with a subfolder (eg: e:wsus).</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h54_54.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h54_54.png" alt=""></a></p> -<p>The other option is to reinstall the WSUS role. If you remove the role, the WID database is not removed, unless you remove that role as well (or manually delete the database). This means that when you reinstall the WSUS role, it will be able to use that same database and any clients that have contacted the WSUS server will immediately show up in the console. The same is true for update metadata. The new WSUS installation will still have the same approvals, denials, etc. as the old installation.</p> -<p>Regardless of what option you choose, I suggest rebooting the server after you make the changes.</p> - + http://localhost:1313/posts/2016-11-18-wsus-update-files-not-downloading/ + This article will discuss an issue regarding WSUS failing to download updates from Microsoft Update servers. You may notice that the home page of your WSUS console states that it has downloaded 0MB of updates: You may also see this event (or similar) in the Event Log. This problem is caused by not specifying a valid path when assigning the WSUS content drive when first installing the role. The first time you load the WSUS console after installing the role, you will be prompted to specify the path to store Windows Update files. - WSUS: An error occurred trying to connect the WSUS server - https://rnemeth90.github.io/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ + http://localhost:1313/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ Thu, 10 Nov 2016 15:18:00 +0000 - - https://rnemeth90.github.io/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ - <p>Ran into this error message when configuring a new WSUS server:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h56_00.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h56_00.png" alt=""></a></p> -<p>Restarted the WSUS, WID, and IIS services to no avail. I even rebooted the server. The WSUS console would work for a short period of time, and then would randomly stop working.</p> -<p>I found that the WSUS app pool in IIS was being disabled anytime new clients connected to the server. I believe this was because the app pool was running out of usable memory.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h28_56.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h28_56.png" alt=""></a></p> -<p>You can manually start the app pool in IIS, but it will continue to crash.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h56_48.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h56_48.png" alt=""></a></p> -<p>The solution for me was to increase the memory limit available for the application pool:</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h57_38.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-12-21_14h57_38.png" alt=""></a></p> -<p>By default it is only configured to use just under 2 GBs. I reconfigured it to use up to 4 GB and the WSUS console has not crashed since. After re-configuring the memory for the application pool, run an IIS reset or reboot the server.</p> -<p><a href="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h31_40.png"><img src="https://rnemeth90.github.io/wp-content/uploads/2016/11/2016-11-09_21h31_40.png" alt=""></a></p> -<p>UPDATE: Setting the Private Memory Limit to “0” will allow the application pool to use whatever amount of memory it needs.</p> - + http://localhost:1313/posts/2016-11-10-wsus-an-error-occurred-trying-to-connect-the-wsus-server/ + Ran into this error message when configuring a new WSUS server: Restarted the WSUS, WID, and IIS services to no avail. I even rebooted the server. The WSUS console would work for a short period of time, and then would randomly stop working. I found that the WSUS app pool in IIS was being disabled anytime new clients connected to the server. I believe this was because the app pool was running out of usable memory. - diff --git a/public/tags/wsus/page/1/index.html b/public/tags/wsus/page/1/index.html index 6bf867ca..56ab5ec8 100644 --- a/public/tags/wsus/page/1/index.html +++ b/public/tags/wsus/page/1/index.html @@ -1,10 +1,10 @@ - + - https://rnemeth90.github.io/tags/wsus/ - + http://localhost:1313/tags/wsus/ + - + diff --git a/resources/_gen/assets/scss/coder-dark.scss_70f8a07cb8b7568202eb18ce456ff884.content b/resources/_gen/assets/scss/coder-dark.scss_70f8a07cb8b7568202eb18ce456ff884.content new file mode 100644 index 00000000..9495c4af --- /dev/null +++ b/resources/_gen/assets/scss/coder-dark.scss_70f8a07cb8b7568202eb18ce456ff884.content @@ -0,0 +1,835 @@ +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 pre code { + background-color: inherit; + color: inherit; } + body.colorscheme-dark code { + background-color: #4f4f4f; + color: #dadada; } + body.colorscheme-dark blockquote { + border-left: 2px solid #424242; } + body.colorscheme-dark th, + body.colorscheme-dark td { + padding: 1.6rem; } + body.colorscheme-dark table { + border-collapse: collapse; } + body.colorscheme-dark table td, + body.colorscheme-dark table th { + border: 2px solid #dadada; } + body.colorscheme-dark table tr:first-child th { + border-top: 0; } + body.colorscheme-dark table tr:last-child td { + border-bottom: 0; } + body.colorscheme-dark table tr td:first-child, + body.colorscheme-dark table tr th:first-child { + border-left: 0; } + body.colorscheme-dark table tr td:last-child, + body.colorscheme-dark table tr th:last-child { + border-right: 0; } + +@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 pre code { + background-color: inherit; + color: inherit; } + body.colorscheme-auto code { + background-color: #4f4f4f; + color: #dadada; } + body.colorscheme-auto blockquote { + border-left: 2px solid #424242; } + body.colorscheme-auto th, + body.colorscheme-auto td { + padding: 1.6rem; } + body.colorscheme-auto table { + border-collapse: collapse; } + body.colorscheme-auto table td, + body.colorscheme-auto table th { + border: 2px solid #dadada; } + body.colorscheme-auto table tr:first-child th { + border-top: 0; } + body.colorscheme-auto table tr:last-child td { + border-bottom: 0; } + body.colorscheme-auto table tr td:first-child, + body.colorscheme-auto table tr th:first-child { + border-left: 0; } + body.colorscheme-auto table tr td:last-child, + body.colorscheme-auto table tr th:last-child { + border-right: 0; } } + +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 .tabs label.tab-label { + background-color: #424242; + border-color: #4f4f4f; } + +body.colorscheme-dark .tabs input.tab-input:checked + label.tab-label { + background-color: #212121; } + +body.colorscheme-dark .tabs .tab-content { + background-color: #212121; + border-color: #4f4f4f; } + +@media (prefers-color-scheme: dark) { + body.colorscheme-auto .tabs label.tab-label { + background-color: #424242; + border-color: #4f4f4f; } + body.colorscheme-auto .tabs input.tab-input:checked + label.tab-label { + background-color: #212121; } + body.colorscheme-auto .tabs .tab-content { + background-color: #212121; + border-color: #4f4f4f; } } + +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; } } +body.colorscheme-dark { + /* Background */ + /* PreWrapper */ + /* Other */ + /* Error */ + /* CodeLine */ + /* LineLink */ + /* LineTableTD */ + /* LineTable */ + /* LineHighlight */ + /* LineNumbersTable */ + /* LineNumbers */ + /* Line */ + /* Keyword */ + /* KeywordConstant */ + /* KeywordDeclaration */ + /* KeywordNamespace */ + /* KeywordPseudo */ + /* KeywordReserved */ + /* KeywordType */ + /* Name */ + /* NameAttribute */ + /* NameBuiltin */ + /* NameBuiltinPseudo */ + /* NameClass */ + /* NameConstant */ + /* NameDecorator */ + /* NameEntity */ + /* NameException */ + /* NameFunction */ + /* NameFunctionMagic */ + /* NameLabel */ + /* NameNamespace */ + /* NameOther */ + /* NameProperty */ + /* NameTag */ + /* NameVariable */ + /* NameVariableClass */ + /* NameVariableGlobal */ + /* NameVariableInstance */ + /* NameVariableMagic */ + /* Literal */ + /* LiteralDate */ + /* LiteralString */ + /* LiteralStringAffix */ + /* LiteralStringBacktick */ + /* LiteralStringChar */ + /* LiteralStringDelimiter */ + /* LiteralStringDoc */ + /* LiteralStringDouble */ + /* LiteralStringEscape */ + /* LiteralStringHeredoc */ + /* LiteralStringInterpol */ + /* LiteralStringOther */ + /* LiteralStringRegex */ + /* LiteralStringSingle */ + /* LiteralStringSymbol */ + /* LiteralNumber */ + /* LiteralNumberBin */ + /* LiteralNumberFloat */ + /* LiteralNumberHex */ + /* LiteralNumberInteger */ + /* LiteralNumberIntegerLong */ + /* LiteralNumberOct */ + /* Operator */ + /* OperatorWord */ + /* Punctuation */ + /* Comment */ + /* CommentHashbang */ + /* CommentMultiline */ + /* CommentSingle */ + /* CommentSpecial */ + /* CommentPreproc */ + /* CommentPreprocFile */ + /* Generic */ + /* GenericDeleted */ + /* GenericEmph */ + /* GenericError */ + /* GenericHeading */ + /* GenericInserted */ + /* GenericOutput */ + /* GenericPrompt */ + /* GenericStrong */ + /* GenericSubheading */ + /* GenericTraceback */ + /* GenericUnderline */ + /* TextWhitespace */ } + body.colorscheme-dark .bg { + color: #c9d1d9; + background-color: #0d1117; } + body.colorscheme-dark .chroma { + color: #c9d1d9; + background-color: #0d1117; } + body.colorscheme-dark .chroma .err { + color: #f85149; } + body.colorscheme-dark .chroma .lnlinks { + outline: none; + text-decoration: none; + color: inherit; } + body.colorscheme-dark .chroma .lntd { + vertical-align: top; + padding: 0; + margin: 0; + border: 0; } + body.colorscheme-dark .chroma .lntable { + border-spacing: 0; + padding: 0; + margin: 0; + border: 0; } + body.colorscheme-dark .chroma .hl { + background-color: #ffffcc; } + body.colorscheme-dark .chroma .lnt { + white-space: pre; + user-select: none; + margin-right: 0.4em; + padding: 0 0.4em 0 0.4em; + color: #64686c; } + body.colorscheme-dark .chroma .ln { + white-space: pre; + user-select: none; + margin-right: 0.4em; + padding: 0 0.4em 0 0.4em; + color: #6e7681; } + body.colorscheme-dark .chroma .line { + display: flex; } + body.colorscheme-dark .chroma .k { + color: #ff7b72; } + body.colorscheme-dark .chroma .kc { + color: #79c0ff; } + body.colorscheme-dark .chroma .kd { + color: #ff7b72; } + body.colorscheme-dark .chroma .kn { + color: #ff7b72; } + body.colorscheme-dark .chroma .kp { + color: #79c0ff; } + body.colorscheme-dark .chroma .kr { + color: #ff7b72; } + body.colorscheme-dark .chroma .kt { + color: #ff7b72; } + body.colorscheme-dark .chroma .nc { + color: #f0883e; + font-weight: bold; } + body.colorscheme-dark .chroma .no { + color: #79c0ff; + font-weight: bold; } + body.colorscheme-dark .chroma .nd { + color: #d2a8ff; + font-weight: bold; } + body.colorscheme-dark .chroma .ni { + color: #ffa657; } + body.colorscheme-dark .chroma .ne { + color: #f0883e; + font-weight: bold; } + body.colorscheme-dark .chroma .nf { + color: #d2a8ff; + font-weight: bold; } + body.colorscheme-dark .chroma .nl { + color: #79c0ff; + font-weight: bold; } + body.colorscheme-dark .chroma .nn { + color: #ff7b72; } + body.colorscheme-dark .chroma .py { + color: #79c0ff; } + body.colorscheme-dark .chroma .nt { + color: #7ee787; } + body.colorscheme-dark .chroma .nv { + color: #79c0ff; } + body.colorscheme-dark .chroma .l { + color: #a5d6ff; } + body.colorscheme-dark .chroma .ld { + color: #79c0ff; } + body.colorscheme-dark .chroma .s { + color: #a5d6ff; } + body.colorscheme-dark .chroma .sa { + color: #79c0ff; } + body.colorscheme-dark .chroma .sb { + color: #a5d6ff; } + body.colorscheme-dark .chroma .sc { + color: #a5d6ff; } + body.colorscheme-dark .chroma .dl { + color: #79c0ff; } + body.colorscheme-dark .chroma .sd { + color: #a5d6ff; } + body.colorscheme-dark .chroma .s2 { + color: #a5d6ff; } + body.colorscheme-dark .chroma .se { + color: #79c0ff; } + body.colorscheme-dark .chroma .sh { + color: #79c0ff; } + body.colorscheme-dark .chroma .si { + color: #a5d6ff; } + body.colorscheme-dark .chroma .sx { + color: #a5d6ff; } + body.colorscheme-dark .chroma .sr { + color: #79c0ff; } + body.colorscheme-dark .chroma .s1 { + color: #a5d6ff; } + body.colorscheme-dark .chroma .ss { + color: #a5d6ff; } + body.colorscheme-dark .chroma .m { + color: #a5d6ff; } + body.colorscheme-dark .chroma .mb { + color: #a5d6ff; } + body.colorscheme-dark .chroma .mf { + color: #a5d6ff; } + body.colorscheme-dark .chroma .mh { + color: #a5d6ff; } + body.colorscheme-dark .chroma .mi { + color: #a5d6ff; } + body.colorscheme-dark .chroma .il { + color: #a5d6ff; } + body.colorscheme-dark .chroma .mo { + color: #a5d6ff; } + body.colorscheme-dark .chroma .o { + color: #ff7b72; + font-weight: bold; } + body.colorscheme-dark .chroma .ow { + color: #ff7b72; + font-weight: bold; } + body.colorscheme-dark .chroma .c { + color: #8b949e; + font-style: italic; } + body.colorscheme-dark .chroma .ch { + color: #8b949e; + font-style: italic; } + body.colorscheme-dark .chroma .cm { + color: #8b949e; + font-style: italic; } + body.colorscheme-dark .chroma .c1 { + color: #8b949e; + font-style: italic; } + body.colorscheme-dark .chroma .cs { + color: #8b949e; + font-weight: bold; + font-style: italic; } + body.colorscheme-dark .chroma .cp { + color: #8b949e; + font-weight: bold; + font-style: italic; } + body.colorscheme-dark .chroma .cpf { + color: #8b949e; + font-weight: bold; + font-style: italic; } + body.colorscheme-dark .chroma .gd { + color: #ffa198; + background-color: #490202; } + body.colorscheme-dark .chroma .ge { + font-style: italic; } + body.colorscheme-dark .chroma .gr { + color: #ffa198; } + body.colorscheme-dark .chroma .gh { + color: #79c0ff; + font-weight: bold; } + body.colorscheme-dark .chroma .gi { + color: #56d364; + background-color: #0f5323; } + body.colorscheme-dark .chroma .go { + color: #8b949e; } + body.colorscheme-dark .chroma .gp { + color: #8b949e; } + body.colorscheme-dark .chroma .gs { + font-weight: bold; } + body.colorscheme-dark .chroma .gu { + color: #79c0ff; } + body.colorscheme-dark .chroma .gt { + color: #ff7b72; } + body.colorscheme-dark .chroma .gl { + text-decoration: underline; } + body.colorscheme-dark .chroma .w { + color: #6e7681; } + +@media (prefers-color-scheme: dark) { + body.colorscheme-auto { + /* Background */ + /* PreWrapper */ + /* Other */ + /* Error */ + /* CodeLine */ + /* LineLink */ + /* LineTableTD */ + /* LineTable */ + /* LineHighlight */ + /* LineNumbersTable */ + /* LineNumbers */ + /* Line */ + /* Keyword */ + /* KeywordConstant */ + /* KeywordDeclaration */ + /* KeywordNamespace */ + /* KeywordPseudo */ + /* KeywordReserved */ + /* KeywordType */ + /* Name */ + /* NameAttribute */ + /* NameBuiltin */ + /* NameBuiltinPseudo */ + /* NameClass */ + /* NameConstant */ + /* NameDecorator */ + /* NameEntity */ + /* NameException */ + /* NameFunction */ + /* NameFunctionMagic */ + /* NameLabel */ + /* NameNamespace */ + /* NameOther */ + /* NameProperty */ + /* NameTag */ + /* NameVariable */ + /* NameVariableClass */ + /* NameVariableGlobal */ + /* NameVariableInstance */ + /* NameVariableMagic */ + /* Literal */ + /* LiteralDate */ + /* LiteralString */ + /* LiteralStringAffix */ + /* LiteralStringBacktick */ + /* LiteralStringChar */ + /* LiteralStringDelimiter */ + /* LiteralStringDoc */ + /* LiteralStringDouble */ + /* LiteralStringEscape */ + /* LiteralStringHeredoc */ + /* LiteralStringInterpol */ + /* LiteralStringOther */ + /* LiteralStringRegex */ + /* LiteralStringSingle */ + /* LiteralStringSymbol */ + /* LiteralNumber */ + /* LiteralNumberBin */ + /* LiteralNumberFloat */ + /* LiteralNumberHex */ + /* LiteralNumberInteger */ + /* LiteralNumberIntegerLong */ + /* LiteralNumberOct */ + /* Operator */ + /* OperatorWord */ + /* Punctuation */ + /* Comment */ + /* CommentHashbang */ + /* CommentMultiline */ + /* CommentSingle */ + /* CommentSpecial */ + /* CommentPreproc */ + /* CommentPreprocFile */ + /* Generic */ + /* GenericDeleted */ + /* GenericEmph */ + /* GenericError */ + /* GenericHeading */ + /* GenericInserted */ + /* GenericOutput */ + /* GenericPrompt */ + /* GenericStrong */ + /* GenericSubheading */ + /* GenericTraceback */ + /* GenericUnderline */ + /* TextWhitespace */ } + body.colorscheme-auto .bg { + color: #c9d1d9; + background-color: #0d1117; } + body.colorscheme-auto .chroma { + color: #c9d1d9; + background-color: #0d1117; } + body.colorscheme-auto .chroma .err { + color: #f85149; } + body.colorscheme-auto .chroma .lnlinks { + outline: none; + text-decoration: none; + color: inherit; } + body.colorscheme-auto .chroma .lntd { + vertical-align: top; + padding: 0; + margin: 0; + border: 0; } + body.colorscheme-auto .chroma .lntable { + border-spacing: 0; + padding: 0; + margin: 0; + border: 0; } + body.colorscheme-auto .chroma .hl { + background-color: #ffffcc; } + body.colorscheme-auto .chroma .lnt { + white-space: pre; + user-select: none; + margin-right: 0.4em; + padding: 0 0.4em 0 0.4em; + color: #64686c; } + body.colorscheme-auto .chroma .ln { + white-space: pre; + user-select: none; + margin-right: 0.4em; + padding: 0 0.4em 0 0.4em; + color: #6e7681; } + body.colorscheme-auto .chroma .line { + display: flex; } + body.colorscheme-auto .chroma .k { + color: #ff7b72; } + body.colorscheme-auto .chroma .kc { + color: #79c0ff; } + body.colorscheme-auto .chroma .kd { + color: #ff7b72; } + body.colorscheme-auto .chroma .kn { + color: #ff7b72; } + body.colorscheme-auto .chroma .kp { + color: #79c0ff; } + body.colorscheme-auto .chroma .kr { + color: #ff7b72; } + body.colorscheme-auto .chroma .kt { + color: #ff7b72; } + body.colorscheme-auto .chroma .nc { + color: #f0883e; + font-weight: bold; } + body.colorscheme-auto .chroma .no { + color: #79c0ff; + font-weight: bold; } + body.colorscheme-auto .chroma .nd { + color: #d2a8ff; + font-weight: bold; } + body.colorscheme-auto .chroma .ni { + color: #ffa657; } + body.colorscheme-auto .chroma .ne { + color: #f0883e; + font-weight: bold; } + body.colorscheme-auto .chroma .nf { + color: #d2a8ff; + font-weight: bold; } + body.colorscheme-auto .chroma .nl { + color: #79c0ff; + font-weight: bold; } + body.colorscheme-auto .chroma .nn { + color: #ff7b72; } + body.colorscheme-auto .chroma .py { + color: #79c0ff; } + body.colorscheme-auto .chroma .nt { + color: #7ee787; } + body.colorscheme-auto .chroma .nv { + color: #79c0ff; } + body.colorscheme-auto .chroma .l { + color: #a5d6ff; } + body.colorscheme-auto .chroma .ld { + color: #79c0ff; } + body.colorscheme-auto .chroma .s { + color: #a5d6ff; } + body.colorscheme-auto .chroma .sa { + color: #79c0ff; } + body.colorscheme-auto .chroma .sb { + color: #a5d6ff; } + body.colorscheme-auto .chroma .sc { + color: #a5d6ff; } + body.colorscheme-auto .chroma .dl { + color: #79c0ff; } + body.colorscheme-auto .chroma .sd { + color: #a5d6ff; } + body.colorscheme-auto .chroma .s2 { + color: #a5d6ff; } + body.colorscheme-auto .chroma .se { + color: #79c0ff; } + body.colorscheme-auto .chroma .sh { + color: #79c0ff; } + body.colorscheme-auto .chroma .si { + color: #a5d6ff; } + body.colorscheme-auto .chroma .sx { + color: #a5d6ff; } + body.colorscheme-auto .chroma .sr { + color: #79c0ff; } + body.colorscheme-auto .chroma .s1 { + color: #a5d6ff; } + body.colorscheme-auto .chroma .ss { + color: #a5d6ff; } + body.colorscheme-auto .chroma .m { + color: #a5d6ff; } + body.colorscheme-auto .chroma .mb { + color: #a5d6ff; } + body.colorscheme-auto .chroma .mf { + color: #a5d6ff; } + body.colorscheme-auto .chroma .mh { + color: #a5d6ff; } + body.colorscheme-auto .chroma .mi { + color: #a5d6ff; } + body.colorscheme-auto .chroma .il { + color: #a5d6ff; } + body.colorscheme-auto .chroma .mo { + color: #a5d6ff; } + body.colorscheme-auto .chroma .o { + color: #ff7b72; + font-weight: bold; } + body.colorscheme-auto .chroma .ow { + color: #ff7b72; + font-weight: bold; } + body.colorscheme-auto .chroma .c { + color: #8b949e; + font-style: italic; } + body.colorscheme-auto .chroma .ch { + color: #8b949e; + font-style: italic; } + body.colorscheme-auto .chroma .cm { + color: #8b949e; + font-style: italic; } + body.colorscheme-auto .chroma .c1 { + color: #8b949e; + font-style: italic; } + body.colorscheme-auto .chroma .cs { + color: #8b949e; + font-weight: bold; + font-style: italic; } + body.colorscheme-auto .chroma .cp { + color: #8b949e; + font-weight: bold; + font-style: italic; } + body.colorscheme-auto .chroma .cpf { + color: #8b949e; + font-weight: bold; + font-style: italic; } + body.colorscheme-auto .chroma .gd { + color: #ffa198; + background-color: #490202; } + body.colorscheme-auto .chroma .ge { + font-style: italic; } + body.colorscheme-auto .chroma .gr { + color: #ffa198; } + body.colorscheme-auto .chroma .gh { + color: #79c0ff; + font-weight: bold; } + body.colorscheme-auto .chroma .gi { + color: #56d364; + background-color: #0f5323; } + body.colorscheme-auto .chroma .go { + color: #8b949e; } + body.colorscheme-auto .chroma .gp { + color: #8b949e; } + body.colorscheme-auto .chroma .gs { + font-weight: bold; } + body.colorscheme-auto .chroma .gu { + color: #79c0ff; } + body.colorscheme-auto .chroma .gt { + color: #ff7b72; } + body.colorscheme-auto .chroma .gl { + text-decoration: underline; } + body.colorscheme-auto .chroma .w { + color: #6e7681; } } + +/*# sourceMappingURL=coder-dark.css.map */ \ No newline at end of file diff --git a/resources/_gen/assets/scss/coder-dark.scss_70f8a07cb8b7568202eb18ce456ff884.json b/resources/_gen/assets/scss/coder-dark.scss_70f8a07cb8b7568202eb18ce456ff884.json new file mode 100644 index 00000000..8a50cdb7 --- /dev/null +++ b/resources/_gen/assets/scss/coder-dark.scss_70f8a07cb8b7568202eb18ce456ff884.json @@ -0,0 +1 @@ +{"Target":"css/coder-dark.css","MediaType":"text/css","Data":{}} \ No newline at end of file diff --git a/resources/_gen/assets/scss/coder.scss_d9b60ee5c2bc7799a5af2e1647965a29.content b/resources/_gen/assets/scss/coder.scss_d9b60ee5c2bc7799a5af2e1647965a29.content new file mode 100644 index 00000000..8c3ae8d1 --- /dev/null +++ b/resources/_gen/assets/scss/coder.scss_d9b60ee5c2bc7799a5af2e1647965a29.content @@ -0,0 +1,13462 @@ +@charset "UTF-8"; +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ +/* Document + ========================================================================== */ +/** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in iOS. + */ +html { + line-height: 1.15; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ } + +/* Sections + ========================================================================== */ +/** + * Remove the margin in all browsers. + */ +body { + margin: 0; } + +/** + * Render the `main` element consistently in IE. + */ +main { + display: block; } + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ +h1 { + font-size: 2em; + margin: 0.67em 0; } + +/* Grouping content + ========================================================================== */ +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ +hr { + box-sizing: content-box; + /* 1 */ + height: 0; + /* 1 */ + overflow: visible; + /* 2 */ } + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ +pre { + font-family: monospace, monospace; + /* 1 */ + font-size: 1em; + /* 2 */ } + +/* Text-level semantics + ========================================================================== */ +/** + * Remove the gray background on active links in IE 10. + */ +a { + background-color: transparent; + word-wrap: break-word; } + +/** + * 1. Remove the bottom border in Chrome 57- + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ +abbr[title] { + border-bottom: none; + /* 1 */ + text-decoration: underline; + /* 2 */ + text-decoration: underline dotted; + /* 2 */ } + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ +b, +strong { + font-weight: bolder; } + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ +code, +kbd, +samp { + font-family: monospace, monospace; + /* 1 */ + font-size: 1em; + /* 2 */ } + +/** + * Add the correct font size in all browsers. + */ +small { + font-size: 80%; } + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; } + +sub { + bottom: -0.25em; } + +sup { + top: -0.5em; } + +/* Embedded content + ========================================================================== */ +/** + * Remove the border on images inside links in IE 10. + */ +img { + border-style: none; } + +/* Forms + ========================================================================== */ +/** + * 1. Change the font styles in all browsers. + * 2. Remove the margin in Firefox and Safari. + */ +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + line-height: 1.15; + /* 1 */ + margin: 0; + /* 2 */ } + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ +button, +input { + /* 1 */ + overflow: visible; } + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ +button, +select { + /* 1 */ + text-transform: none; } + +/** + * Correct the inability to style clickable types in iOS and Safari. + */ +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; } + +/** + * Remove the inner border and padding in Firefox. + */ +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; } + +/** + * Restore the focus styles unset by the previous rule. + */ +button:-moz-focusring, +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; } + +/** + * Correct the padding in Firefox. + */ +fieldset { + padding: 0.35em 0.75em 0.625em; } + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ +legend { + box-sizing: border-box; + /* 1 */ + color: inherit; + /* 2 */ + display: table; + /* 1 */ + max-width: 100%; + /* 1 */ + padding: 0; + /* 3 */ + white-space: normal; + /* 1 */ } + +/** + * Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ +progress { + vertical-align: baseline; } + +/** + * Remove the default vertical scrollbar in IE 10+. + */ +textarea { + overflow: auto; } + +/** + * 1. Add the correct box sizing in IE 10. + * 2. Remove the padding in IE 10. + */ +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; + /* 1 */ + padding: 0; + /* 2 */ } + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; } + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ +[type="search"] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ } + +/** + * Remove the inner padding in Chrome and Safari on macOS. + */ +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; } + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ +::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ } + +/* Interactive + ========================================================================== */ +/* + * Add the correct display in Edge, IE 10+, and Firefox. + */ +details { + display: block; } + +/* + * Add the correct display in all browsers. + */ +summary { + display: list-item; } + +/* Misc + ========================================================================== */ +/** + * Add the correct display in IE 10+. + */ +template { + display: none; } + +/** + * Add the correct display in IE 10. + */ +[hidden] { + display: none; } + +/*! + * Font Awesome Free 6.7.1 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +.fa { + font-family: var(--fa-style-family, "Font Awesome 6 Free"); + font-weight: var(--fa-style, 900); } + +.fas, +.far, +.fab, +.fa-solid, +.content article a:where(.external-link):not(:has(img)):after, +.fa-regular, +.fa-brands, +.fa { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: var(--fa-display, inline-block); + font-style: normal; + font-variant: normal; + line-height: 1; + text-rendering: auto; } + +.fas::before, +.far::before, +.fab::before, +.fa-solid::before, +.fa-regular::before, +.fa-brands::before, +.fa::before { + content: var(--fa); } + +.fa-classic, +.fas, +.fa-solid, +.content article a:where(.external-link):not(:has(img)):after, +.far, +.fa-regular { + font-family: 'Font Awesome 6 Free'; } + +.fa-brands, +.fab { + font-family: 'Font Awesome 6 Brands'; } + +.content article a:where(.external-link):not(:has(img)):after { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + display: inline-block; + font-style: normal; + font-variant: normal; + font-weight: normal; + line-height: 1; } + +.fa-1x { + font-size: 1em; } + +.fa-2x { + font-size: 2em; } + +.fa-3x { + font-size: 3em; } + +.fa-4x { + font-size: 4em; } + +.fa-5x { + font-size: 5em; } + +.fa-6x { + font-size: 6em; } + +.fa-7x { + font-size: 7em; } + +.fa-8x { + font-size: 8em; } + +.fa-9x { + font-size: 9em; } + +.fa-10x { + font-size: 10em; } + +.fa-2xs { + font-size: 0.625em; + line-height: 0.1em; + vertical-align: 0.225em; } + +.fa-xs { + font-size: 0.75em; + line-height: 0.08333333em; + vertical-align: 0.125em; } + +.fa-sm { + font-size: 0.875em; + line-height: 0.07142857em; + vertical-align: 0.05357143em; } + +.fa-lg { + font-size: 1.25em; + line-height: 0.05em; + vertical-align: -0.075em; } + +.fa-xl { + font-size: 1.5em; + line-height: 0.04166667em; + vertical-align: -0.125em; } + +.fa-2xl { + font-size: 2em; + line-height: 0.03125em; + vertical-align: -0.1875em; } + +.fa-fw { + text-align: center; + width: 1.25em; } + +.fa-ul { + list-style-type: none; + margin-left: var(--fa-li-margin, 2.5em); + padding-left: 0; } + .fa-ul > li { + position: relative; } + +.fa-li { + left: calc(-1 * var(--fa-li-width, 2em)); + position: absolute; + text-align: center; + width: var(--fa-li-width, 2em); + line-height: inherit; } + +.fa-border { + border-color: var(--fa-border-color, #eee); + border-radius: var(--fa-border-radius, 0.1em); + border-style: var(--fa-border-style, solid); + border-width: var(--fa-border-width, 0.08em); + padding: var(--fa-border-padding, 0.2em 0.25em 0.15em); } + +.fa-pull-left { + float: left; + margin-right: var(--fa-pull-margin, 0.3em); } + +.fa-pull-right { + float: right; + margin-left: var(--fa-pull-margin, 0.3em); } + +.fa-beat { + animation-name: fa-beat; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, ease-in-out); } + +.fa-bounce { + animation-name: fa-bounce; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); } + +.fa-fade { + animation-name: fa-fade; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); } + +.fa-beat-fade { + animation-name: fa-beat-fade; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); } + +.fa-flip { + animation-name: fa-flip; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, ease-in-out); } + +.fa-shake { + animation-name: fa-shake; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, linear); } + +.fa-spin { + animation-name: fa-spin; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 2s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, linear); } + +.fa-spin-reverse { + --fa-animation-direction: reverse; } + +.fa-pulse, +.fa-spin-pulse { + animation-name: fa-spin; + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, steps(8)); } + +@media (prefers-reduced-motion: reduce) { + .fa-beat, + .fa-bounce, + .fa-fade, + .fa-beat-fade, + .fa-flip, + .fa-pulse, + .fa-shake, + .fa-spin, + .fa-spin-pulse { + animation-delay: -1ms; + animation-duration: 1ms; + animation-iteration-count: 1; + transition-delay: 0s; + transition-duration: 0s; } } + +@keyframes fa-beat { + 0%, 90% { + transform: scale(1); } + 45% { + transform: scale(var(--fa-beat-scale, 1.25)); } } + +@keyframes fa-bounce { + 0% { + transform: scale(1, 1) translateY(0); } + 10% { + transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); } + 30% { + transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); } + 50% { + transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); } + 57% { + transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); } + 64% { + transform: scale(1, 1) translateY(0); } + 100% { + transform: scale(1, 1) translateY(0); } } + +@keyframes fa-fade { + 50% { + opacity: var(--fa-fade-opacity, 0.4); } } + +@keyframes fa-beat-fade { + 0%, 100% { + opacity: var(--fa-beat-fade-opacity, 0.4); + transform: scale(1); } + 50% { + opacity: 1; + transform: scale(var(--fa-beat-fade-scale, 1.125)); } } + +@keyframes fa-flip { + 50% { + transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); } } + +@keyframes fa-shake { + 0% { + transform: rotate(-15deg); } + 4% { + transform: rotate(15deg); } + 8%, 24% { + transform: rotate(-18deg); } + 12%, 28% { + transform: rotate(18deg); } + 16% { + transform: rotate(-22deg); } + 20% { + transform: rotate(22deg); } + 32% { + transform: rotate(-12deg); } + 36% { + transform: rotate(12deg); } + 40%, 100% { + transform: rotate(0deg); } } + +@keyframes fa-spin { + 0% { + transform: rotate(0deg); } + 100% { + transform: rotate(360deg); } } + +.fa-rotate-90 { + transform: rotate(90deg); } + +.fa-rotate-180 { + transform: rotate(180deg); } + +.fa-rotate-270 { + transform: rotate(270deg); } + +.fa-flip-horizontal { + transform: scale(-1, 1); } + +.fa-flip-vertical { + transform: scale(1, -1); } + +.fa-flip-both, +.fa-flip-horizontal.fa-flip-vertical { + transform: scale(-1, -1); } + +.fa-rotate-by { + transform: rotate(var(--fa-rotate-angle, 0)); } + +.fa-stack { + display: inline-block; + height: 2em; + line-height: 2em; + position: relative; + vertical-align: middle; + width: 2.5em; } + +.fa-stack-1x, +.fa-stack-2x { + left: 0; + position: absolute; + text-align: center; + width: 100%; + z-index: var(--fa-stack-z-index, auto); } + +.fa-stack-1x { + line-height: inherit; } + +.fa-stack-2x { + font-size: 2em; } + +.fa-inverse { + color: var(--fa-inverse, #fff); } + +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen +readers do not read off random characters that represent icons */ +.fa-0 { + --fa: "\30"; + --fa--fa: "\30\30"; } + +.fa-1 { + --fa: "\31"; + --fa--fa: "\31\31"; } + +.fa-2 { + --fa: "\32"; + --fa--fa: "\32\32"; } + +.fa-3 { + --fa: "\33"; + --fa--fa: "\33\33"; } + +.fa-4 { + --fa: "\34"; + --fa--fa: "\34\34"; } + +.fa-5 { + --fa: "\35"; + --fa--fa: "\35\35"; } + +.fa-6 { + --fa: "\36"; + --fa--fa: "\36\36"; } + +.fa-7 { + --fa: "\37"; + --fa--fa: "\37\37"; } + +.fa-8 { + --fa: "\38"; + --fa--fa: "\38\38"; } + +.fa-9 { + --fa: "\39"; + --fa--fa: "\39\39"; } + +.fa-fill-drip { + --fa: "\f576"; + --fa--fa: "\f576\f576"; } + +.fa-arrows-to-circle { + --fa: "\e4bd"; + --fa--fa: "\e4bd\e4bd"; } + +.fa-circle-chevron-right { + --fa: "\f138"; + --fa--fa: "\f138\f138"; } + +.fa-chevron-circle-right { + --fa: "\f138"; + --fa--fa: "\f138\f138"; } + +.fa-at { + --fa: "\40"; + --fa--fa: "\40\40"; } + +.fa-trash-can { + --fa: "\f2ed"; + --fa--fa: "\f2ed\f2ed"; } + +.fa-trash-alt { + --fa: "\f2ed"; + --fa--fa: "\f2ed\f2ed"; } + +.fa-text-height { + --fa: "\f034"; + --fa--fa: "\f034\f034"; } + +.fa-user-xmark { + --fa: "\f235"; + --fa--fa: "\f235\f235"; } + +.fa-user-times { + --fa: "\f235"; + --fa--fa: "\f235\f235"; } + +.fa-stethoscope { + --fa: "\f0f1"; + --fa--fa: "\f0f1\f0f1"; } + +.fa-message { + --fa: "\f27a"; + --fa--fa: "\f27a\f27a"; } + +.fa-comment-alt { + --fa: "\f27a"; + --fa--fa: "\f27a\f27a"; } + +.fa-info { + --fa: "\f129"; + --fa--fa: "\f129\f129"; } + +.fa-down-left-and-up-right-to-center { + --fa: "\f422"; + --fa--fa: "\f422\f422"; } + +.fa-compress-alt { + --fa: "\f422"; + --fa--fa: "\f422\f422"; } + +.fa-explosion { + --fa: "\e4e9"; + --fa--fa: "\e4e9\e4e9"; } + +.fa-file-lines { + --fa: "\f15c"; + --fa--fa: "\f15c\f15c"; } + +.fa-file-alt { + --fa: "\f15c"; + --fa--fa: "\f15c\f15c"; } + +.fa-file-text { + --fa: "\f15c"; + --fa--fa: "\f15c\f15c"; } + +.fa-wave-square { + --fa: "\f83e"; + --fa--fa: "\f83e\f83e"; } + +.fa-ring { + --fa: "\f70b"; + --fa--fa: "\f70b\f70b"; } + +.fa-building-un { + --fa: "\e4d9"; + --fa--fa: "\e4d9\e4d9"; } + +.fa-dice-three { + --fa: "\f527"; + --fa--fa: "\f527\f527"; } + +.fa-calendar-days { + --fa: "\f073"; + --fa--fa: "\f073\f073"; } + +.fa-calendar-alt { + --fa: "\f073"; + --fa--fa: "\f073\f073"; } + +.fa-anchor-circle-check { + --fa: "\e4aa"; + --fa--fa: "\e4aa\e4aa"; } + +.fa-building-circle-arrow-right { + --fa: "\e4d1"; + --fa--fa: "\e4d1\e4d1"; } + +.fa-volleyball { + --fa: "\f45f"; + --fa--fa: "\f45f\f45f"; } + +.fa-volleyball-ball { + --fa: "\f45f"; + --fa--fa: "\f45f\f45f"; } + +.fa-arrows-up-to-line { + --fa: "\e4c2"; + --fa--fa: "\e4c2\e4c2"; } + +.fa-sort-down { + --fa: "\f0dd"; + --fa--fa: "\f0dd\f0dd"; } + +.fa-sort-desc { + --fa: "\f0dd"; + --fa--fa: "\f0dd\f0dd"; } + +.fa-circle-minus { + --fa: "\f056"; + --fa--fa: "\f056\f056"; } + +.fa-minus-circle { + --fa: "\f056"; + --fa--fa: "\f056\f056"; } + +.fa-door-open { + --fa: "\f52b"; + --fa--fa: "\f52b\f52b"; } + +.fa-right-from-bracket { + --fa: "\f2f5"; + --fa--fa: "\f2f5\f2f5"; } + +.fa-sign-out-alt { + --fa: "\f2f5"; + --fa--fa: "\f2f5\f2f5"; } + +.fa-atom { + --fa: "\f5d2"; + --fa--fa: "\f5d2\f5d2"; } + +.fa-soap { + --fa: "\e06e"; + --fa--fa: "\e06e\e06e"; } + +.fa-icons { + --fa: "\f86d"; + --fa--fa: "\f86d\f86d"; } + +.fa-heart-music-camera-bolt { + --fa: "\f86d"; + --fa--fa: "\f86d\f86d"; } + +.fa-microphone-lines-slash { + --fa: "\f539"; + --fa--fa: "\f539\f539"; } + +.fa-microphone-alt-slash { + --fa: "\f539"; + --fa--fa: "\f539\f539"; } + +.fa-bridge-circle-check { + --fa: "\e4c9"; + --fa--fa: "\e4c9\e4c9"; } + +.fa-pump-medical { + --fa: "\e06a"; + --fa--fa: "\e06a\e06a"; } + +.fa-fingerprint { + --fa: "\f577"; + --fa--fa: "\f577\f577"; } + +.fa-hand-point-right { + --fa: "\f0a4"; + --fa--fa: "\f0a4\f0a4"; } + +.fa-magnifying-glass-location { + --fa: "\f689"; + --fa--fa: "\f689\f689"; } + +.fa-search-location { + --fa: "\f689"; + --fa--fa: "\f689\f689"; } + +.fa-forward-step { + --fa: "\f051"; + --fa--fa: "\f051\f051"; } + +.fa-step-forward { + --fa: "\f051"; + --fa--fa: "\f051\f051"; } + +.fa-face-smile-beam { + --fa: "\f5b8"; + --fa--fa: "\f5b8\f5b8"; } + +.fa-smile-beam { + --fa: "\f5b8"; + --fa--fa: "\f5b8\f5b8"; } + +.fa-flag-checkered { + --fa: "\f11e"; + --fa--fa: "\f11e\f11e"; } + +.fa-football { + --fa: "\f44e"; + --fa--fa: "\f44e\f44e"; } + +.fa-football-ball { + --fa: "\f44e"; + --fa--fa: "\f44e\f44e"; } + +.fa-school-circle-exclamation { + --fa: "\e56c"; + --fa--fa: "\e56c\e56c"; } + +.fa-crop { + --fa: "\f125"; + --fa--fa: "\f125\f125"; } + +.fa-angles-down { + --fa: "\f103"; + --fa--fa: "\f103\f103"; } + +.fa-angle-double-down { + --fa: "\f103"; + --fa--fa: "\f103\f103"; } + +.fa-users-rectangle { + --fa: "\e594"; + --fa--fa: "\e594\e594"; } + +.fa-people-roof { + --fa: "\e537"; + --fa--fa: "\e537\e537"; } + +.fa-people-line { + --fa: "\e534"; + --fa--fa: "\e534\e534"; } + +.fa-beer-mug-empty { + --fa: "\f0fc"; + --fa--fa: "\f0fc\f0fc"; } + +.fa-beer { + --fa: "\f0fc"; + --fa--fa: "\f0fc\f0fc"; } + +.fa-diagram-predecessor { + --fa: "\e477"; + --fa--fa: "\e477\e477"; } + +.fa-arrow-up-long { + --fa: "\f176"; + --fa--fa: "\f176\f176"; } + +.fa-long-arrow-up { + --fa: "\f176"; + --fa--fa: "\f176\f176"; } + +.fa-fire-flame-simple { + --fa: "\f46a"; + --fa--fa: "\f46a\f46a"; } + +.fa-burn { + --fa: "\f46a"; + --fa--fa: "\f46a\f46a"; } + +.fa-person { + --fa: "\f183"; + --fa--fa: "\f183\f183"; } + +.fa-male { + --fa: "\f183"; + --fa--fa: "\f183\f183"; } + +.fa-laptop { + --fa: "\f109"; + --fa--fa: "\f109\f109"; } + +.fa-file-csv { + --fa: "\f6dd"; + --fa--fa: "\f6dd\f6dd"; } + +.fa-menorah { + --fa: "\f676"; + --fa--fa: "\f676\f676"; } + +.fa-truck-plane { + --fa: "\e58f"; + --fa--fa: "\e58f\e58f"; } + +.fa-record-vinyl { + --fa: "\f8d9"; + --fa--fa: "\f8d9\f8d9"; } + +.fa-face-grin-stars { + --fa: "\f587"; + --fa--fa: "\f587\f587"; } + +.fa-grin-stars { + --fa: "\f587"; + --fa--fa: "\f587\f587"; } + +.fa-bong { + --fa: "\f55c"; + --fa--fa: "\f55c\f55c"; } + +.fa-spaghetti-monster-flying { + --fa: "\f67b"; + --fa--fa: "\f67b\f67b"; } + +.fa-pastafarianism { + --fa: "\f67b"; + --fa--fa: "\f67b\f67b"; } + +.fa-arrow-down-up-across-line { + --fa: "\e4af"; + --fa--fa: "\e4af\e4af"; } + +.fa-spoon { + --fa: "\f2e5"; + --fa--fa: "\f2e5\f2e5"; } + +.fa-utensil-spoon { + --fa: "\f2e5"; + --fa--fa: "\f2e5\f2e5"; } + +.fa-jar-wheat { + --fa: "\e517"; + --fa--fa: "\e517\e517"; } + +.fa-envelopes-bulk { + --fa: "\f674"; + --fa--fa: "\f674\f674"; } + +.fa-mail-bulk { + --fa: "\f674"; + --fa--fa: "\f674\f674"; } + +.fa-file-circle-exclamation { + --fa: "\e4eb"; + --fa--fa: "\e4eb\e4eb"; } + +.fa-circle-h { + --fa: "\f47e"; + --fa--fa: "\f47e\f47e"; } + +.fa-hospital-symbol { + --fa: "\f47e"; + --fa--fa: "\f47e\f47e"; } + +.fa-pager { + --fa: "\f815"; + --fa--fa: "\f815\f815"; } + +.fa-address-book { + --fa: "\f2b9"; + --fa--fa: "\f2b9\f2b9"; } + +.fa-contact-book { + --fa: "\f2b9"; + --fa--fa: "\f2b9\f2b9"; } + +.fa-strikethrough { + --fa: "\f0cc"; + --fa--fa: "\f0cc\f0cc"; } + +.fa-k { + --fa: "\4b"; + --fa--fa: "\4b\4b"; } + +.fa-landmark-flag { + --fa: "\e51c"; + --fa--fa: "\e51c\e51c"; } + +.fa-pencil { + --fa: "\f303"; + --fa--fa: "\f303\f303"; } + +.fa-pencil-alt { + --fa: "\f303"; + --fa--fa: "\f303\f303"; } + +.fa-backward { + --fa: "\f04a"; + --fa--fa: "\f04a\f04a"; } + +.fa-caret-right { + --fa: "\f0da"; + --fa--fa: "\f0da\f0da"; } + +.fa-comments { + --fa: "\f086"; + --fa--fa: "\f086\f086"; } + +.fa-paste { + --fa: "\f0ea"; + --fa--fa: "\f0ea\f0ea"; } + +.fa-file-clipboard { + --fa: "\f0ea"; + --fa--fa: "\f0ea\f0ea"; } + +.fa-code-pull-request { + --fa: "\e13c"; + --fa--fa: "\e13c\e13c"; } + +.fa-clipboard-list { + --fa: "\f46d"; + --fa--fa: "\f46d\f46d"; } + +.fa-truck-ramp-box { + --fa: "\f4de"; + --fa--fa: "\f4de\f4de"; } + +.fa-truck-loading { + --fa: "\f4de"; + --fa--fa: "\f4de\f4de"; } + +.fa-user-check { + --fa: "\f4fc"; + --fa--fa: "\f4fc\f4fc"; } + +.fa-vial-virus { + --fa: "\e597"; + --fa--fa: "\e597\e597"; } + +.fa-sheet-plastic { + --fa: "\e571"; + --fa--fa: "\e571\e571"; } + +.fa-blog { + --fa: "\f781"; + --fa--fa: "\f781\f781"; } + +.fa-user-ninja { + --fa: "\f504"; + --fa--fa: "\f504\f504"; } + +.fa-person-arrow-up-from-line { + --fa: "\e539"; + --fa--fa: "\e539\e539"; } + +.fa-scroll-torah { + --fa: "\f6a0"; + --fa--fa: "\f6a0\f6a0"; } + +.fa-torah { + --fa: "\f6a0"; + --fa--fa: "\f6a0\f6a0"; } + +.fa-broom-ball { + --fa: "\f458"; + --fa--fa: "\f458\f458"; } + +.fa-quidditch { + --fa: "\f458"; + --fa--fa: "\f458\f458"; } + +.fa-quidditch-broom-ball { + --fa: "\f458"; + --fa--fa: "\f458\f458"; } + +.fa-toggle-off { + --fa: "\f204"; + --fa--fa: "\f204\f204"; } + +.fa-box-archive { + --fa: "\f187"; + --fa--fa: "\f187\f187"; } + +.fa-archive { + --fa: "\f187"; + --fa--fa: "\f187\f187"; } + +.fa-person-drowning { + --fa: "\e545"; + --fa--fa: "\e545\e545"; } + +.fa-arrow-down-9-1 { + --fa: "\f886"; + --fa--fa: "\f886\f886"; } + +.fa-sort-numeric-desc { + --fa: "\f886"; + --fa--fa: "\f886\f886"; } + +.fa-sort-numeric-down-alt { + --fa: "\f886"; + --fa--fa: "\f886\f886"; } + +.fa-face-grin-tongue-squint { + --fa: "\f58a"; + --fa--fa: "\f58a\f58a"; } + +.fa-grin-tongue-squint { + --fa: "\f58a"; + --fa--fa: "\f58a\f58a"; } + +.fa-spray-can { + --fa: "\f5bd"; + --fa--fa: "\f5bd\f5bd"; } + +.fa-truck-monster { + --fa: "\f63b"; + --fa--fa: "\f63b\f63b"; } + +.fa-w { + --fa: "\57"; + --fa--fa: "\57\57"; } + +.fa-earth-africa { + --fa: "\f57c"; + --fa--fa: "\f57c\f57c"; } + +.fa-globe-africa { + --fa: "\f57c"; + --fa--fa: "\f57c\f57c"; } + +.fa-rainbow { + --fa: "\f75b"; + --fa--fa: "\f75b\f75b"; } + +.fa-circle-notch { + --fa: "\f1ce"; + --fa--fa: "\f1ce\f1ce"; } + +.fa-tablet-screen-button { + --fa: "\f3fa"; + --fa--fa: "\f3fa\f3fa"; } + +.fa-tablet-alt { + --fa: "\f3fa"; + --fa--fa: "\f3fa\f3fa"; } + +.fa-paw { + --fa: "\f1b0"; + --fa--fa: "\f1b0\f1b0"; } + +.fa-cloud { + --fa: "\f0c2"; + --fa--fa: "\f0c2\f0c2"; } + +.fa-trowel-bricks { + --fa: "\e58a"; + --fa--fa: "\e58a\e58a"; } + +.fa-face-flushed { + --fa: "\f579"; + --fa--fa: "\f579\f579"; } + +.fa-flushed { + --fa: "\f579"; + --fa--fa: "\f579\f579"; } + +.fa-hospital-user { + --fa: "\f80d"; + --fa--fa: "\f80d\f80d"; } + +.fa-tent-arrow-left-right { + --fa: "\e57f"; + --fa--fa: "\e57f\e57f"; } + +.fa-gavel { + --fa: "\f0e3"; + --fa--fa: "\f0e3\f0e3"; } + +.fa-legal { + --fa: "\f0e3"; + --fa--fa: "\f0e3\f0e3"; } + +.fa-binoculars { + --fa: "\f1e5"; + --fa--fa: "\f1e5\f1e5"; } + +.fa-microphone-slash { + --fa: "\f131"; + --fa--fa: "\f131\f131"; } + +.fa-box-tissue { + --fa: "\e05b"; + --fa--fa: "\e05b\e05b"; } + +.fa-motorcycle { + --fa: "\f21c"; + --fa--fa: "\f21c\f21c"; } + +.fa-bell-concierge { + --fa: "\f562"; + --fa--fa: "\f562\f562"; } + +.fa-concierge-bell { + --fa: "\f562"; + --fa--fa: "\f562\f562"; } + +.fa-pen-ruler { + --fa: "\f5ae"; + --fa--fa: "\f5ae\f5ae"; } + +.fa-pencil-ruler { + --fa: "\f5ae"; + --fa--fa: "\f5ae\f5ae"; } + +.fa-people-arrows { + --fa: "\e068"; + --fa--fa: "\e068\e068"; } + +.fa-people-arrows-left-right { + --fa: "\e068"; + --fa--fa: "\e068\e068"; } + +.fa-mars-and-venus-burst { + --fa: "\e523"; + --fa--fa: "\e523\e523"; } + +.fa-square-caret-right { + --fa: "\f152"; + --fa--fa: "\f152\f152"; } + +.fa-caret-square-right { + --fa: "\f152"; + --fa--fa: "\f152\f152"; } + +.fa-scissors { + --fa: "\f0c4"; + --fa--fa: "\f0c4\f0c4"; } + +.fa-cut { + --fa: "\f0c4"; + --fa--fa: "\f0c4\f0c4"; } + +.fa-sun-plant-wilt { + --fa: "\e57a"; + --fa--fa: "\e57a\e57a"; } + +.fa-toilets-portable { + --fa: "\e584"; + --fa--fa: "\e584\e584"; } + +.fa-hockey-puck { + --fa: "\f453"; + --fa--fa: "\f453\f453"; } + +.fa-table { + --fa: "\f0ce"; + --fa--fa: "\f0ce\f0ce"; } + +.fa-magnifying-glass-arrow-right { + --fa: "\e521"; + --fa--fa: "\e521\e521"; } + +.fa-tachograph-digital { + --fa: "\f566"; + --fa--fa: "\f566\f566"; } + +.fa-digital-tachograph { + --fa: "\f566"; + --fa--fa: "\f566\f566"; } + +.fa-users-slash { + --fa: "\e073"; + --fa--fa: "\e073\e073"; } + +.fa-clover { + --fa: "\e139"; + --fa--fa: "\e139\e139"; } + +.fa-reply { + --fa: "\f3e5"; + --fa--fa: "\f3e5\f3e5"; } + +.fa-mail-reply { + --fa: "\f3e5"; + --fa--fa: "\f3e5\f3e5"; } + +.fa-star-and-crescent { + --fa: "\f699"; + --fa--fa: "\f699\f699"; } + +.fa-house-fire { + --fa: "\e50c"; + --fa--fa: "\e50c\e50c"; } + +.fa-square-minus { + --fa: "\f146"; + --fa--fa: "\f146\f146"; } + +.fa-minus-square { + --fa: "\f146"; + --fa--fa: "\f146\f146"; } + +.fa-helicopter { + --fa: "\f533"; + --fa--fa: "\f533\f533"; } + +.fa-compass { + --fa: "\f14e"; + --fa--fa: "\f14e\f14e"; } + +.fa-square-caret-down { + --fa: "\f150"; + --fa--fa: "\f150\f150"; } + +.fa-caret-square-down { + --fa: "\f150"; + --fa--fa: "\f150\f150"; } + +.fa-file-circle-question { + --fa: "\e4ef"; + --fa--fa: "\e4ef\e4ef"; } + +.fa-laptop-code { + --fa: "\f5fc"; + --fa--fa: "\f5fc\f5fc"; } + +.fa-swatchbook { + --fa: "\f5c3"; + --fa--fa: "\f5c3\f5c3"; } + +.fa-prescription-bottle { + --fa: "\f485"; + --fa--fa: "\f485\f485"; } + +.fa-bars { + --fa: "\f0c9"; + --fa--fa: "\f0c9\f0c9"; } + +.fa-navicon { + --fa: "\f0c9"; + --fa--fa: "\f0c9\f0c9"; } + +.fa-people-group { + --fa: "\e533"; + --fa--fa: "\e533\e533"; } + +.fa-hourglass-end { + --fa: "\f253"; + --fa--fa: "\f253\f253"; } + +.fa-hourglass-3 { + --fa: "\f253"; + --fa--fa: "\f253\f253"; } + +.fa-heart-crack { + --fa: "\f7a9"; + --fa--fa: "\f7a9\f7a9"; } + +.fa-heart-broken { + --fa: "\f7a9"; + --fa--fa: "\f7a9\f7a9"; } + +.fa-square-up-right { + --fa: "\f360"; + --fa--fa: "\f360\f360"; } + +.fa-external-link-square-alt { + --fa: "\f360"; + --fa--fa: "\f360\f360"; } + +.fa-face-kiss-beam { + --fa: "\f597"; + --fa--fa: "\f597\f597"; } + +.fa-kiss-beam { + --fa: "\f597"; + --fa--fa: "\f597\f597"; } + +.fa-film { + --fa: "\f008"; + --fa--fa: "\f008\f008"; } + +.fa-ruler-horizontal { + --fa: "\f547"; + --fa--fa: "\f547\f547"; } + +.fa-people-robbery { + --fa: "\e536"; + --fa--fa: "\e536\e536"; } + +.fa-lightbulb { + --fa: "\f0eb"; + --fa--fa: "\f0eb\f0eb"; } + +.fa-caret-left { + --fa: "\f0d9"; + --fa--fa: "\f0d9\f0d9"; } + +.fa-circle-exclamation { + --fa: "\f06a"; + --fa--fa: "\f06a\f06a"; } + +.fa-exclamation-circle { + --fa: "\f06a"; + --fa--fa: "\f06a\f06a"; } + +.fa-school-circle-xmark { + --fa: "\e56d"; + --fa--fa: "\e56d\e56d"; } + +.fa-arrow-right-from-bracket { + --fa: "\f08b"; + --fa--fa: "\f08b\f08b"; } + +.fa-sign-out { + --fa: "\f08b"; + --fa--fa: "\f08b\f08b"; } + +.fa-circle-chevron-down { + --fa: "\f13a"; + --fa--fa: "\f13a\f13a"; } + +.fa-chevron-circle-down { + --fa: "\f13a"; + --fa--fa: "\f13a\f13a"; } + +.fa-unlock-keyhole { + --fa: "\f13e"; + --fa--fa: "\f13e\f13e"; } + +.fa-unlock-alt { + --fa: "\f13e"; + --fa--fa: "\f13e\f13e"; } + +.fa-cloud-showers-heavy { + --fa: "\f740"; + --fa--fa: "\f740\f740"; } + +.fa-headphones-simple { + --fa: "\f58f"; + --fa--fa: "\f58f\f58f"; } + +.fa-headphones-alt { + --fa: "\f58f"; + --fa--fa: "\f58f\f58f"; } + +.fa-sitemap { + --fa: "\f0e8"; + --fa--fa: "\f0e8\f0e8"; } + +.fa-circle-dollar-to-slot { + --fa: "\f4b9"; + --fa--fa: "\f4b9\f4b9"; } + +.fa-donate { + --fa: "\f4b9"; + --fa--fa: "\f4b9\f4b9"; } + +.fa-memory { + --fa: "\f538"; + --fa--fa: "\f538\f538"; } + +.fa-road-spikes { + --fa: "\e568"; + --fa--fa: "\e568\e568"; } + +.fa-fire-burner { + --fa: "\e4f1"; + --fa--fa: "\e4f1\e4f1"; } + +.fa-flag { + --fa: "\f024"; + --fa--fa: "\f024\f024"; } + +.fa-hanukiah { + --fa: "\f6e6"; + --fa--fa: "\f6e6\f6e6"; } + +.fa-feather { + --fa: "\f52d"; + --fa--fa: "\f52d\f52d"; } + +.fa-volume-low { + --fa: "\f027"; + --fa--fa: "\f027\f027"; } + +.fa-volume-down { + --fa: "\f027"; + --fa--fa: "\f027\f027"; } + +.fa-comment-slash { + --fa: "\f4b3"; + --fa--fa: "\f4b3\f4b3"; } + +.fa-cloud-sun-rain { + --fa: "\f743"; + --fa--fa: "\f743\f743"; } + +.fa-compress { + --fa: "\f066"; + --fa--fa: "\f066\f066"; } + +.fa-wheat-awn { + --fa: "\e2cd"; + --fa--fa: "\e2cd\e2cd"; } + +.fa-wheat-alt { + --fa: "\e2cd"; + --fa--fa: "\e2cd\e2cd"; } + +.fa-ankh { + --fa: "\f644"; + --fa--fa: "\f644\f644"; } + +.fa-hands-holding-child { + --fa: "\e4fa"; + --fa--fa: "\e4fa\e4fa"; } + +.fa-asterisk { + --fa: "\2a"; + --fa--fa: "\2a\2a"; } + +.fa-square-check { + --fa: "\f14a"; + --fa--fa: "\f14a\f14a"; } + +.fa-check-square { + --fa: "\f14a"; + --fa--fa: "\f14a\f14a"; } + +.fa-peseta-sign { + --fa: "\e221"; + --fa--fa: "\e221\e221"; } + +.fa-heading { + --fa: "\f1dc"; + --fa--fa: "\f1dc\f1dc"; } + +.fa-header { + --fa: "\f1dc"; + --fa--fa: "\f1dc\f1dc"; } + +.fa-ghost { + --fa: "\f6e2"; + --fa--fa: "\f6e2\f6e2"; } + +.fa-list { + --fa: "\f03a"; + --fa--fa: "\f03a\f03a"; } + +.fa-list-squares { + --fa: "\f03a"; + --fa--fa: "\f03a\f03a"; } + +.fa-square-phone-flip { + --fa: "\f87b"; + --fa--fa: "\f87b\f87b"; } + +.fa-phone-square-alt { + --fa: "\f87b"; + --fa--fa: "\f87b\f87b"; } + +.fa-cart-plus { + --fa: "\f217"; + --fa--fa: "\f217\f217"; } + +.fa-gamepad { + --fa: "\f11b"; + --fa--fa: "\f11b\f11b"; } + +.fa-circle-dot { + --fa: "\f192"; + --fa--fa: "\f192\f192"; } + +.fa-dot-circle { + --fa: "\f192"; + --fa--fa: "\f192\f192"; } + +.fa-face-dizzy { + --fa: "\f567"; + --fa--fa: "\f567\f567"; } + +.fa-dizzy { + --fa: "\f567"; + --fa--fa: "\f567\f567"; } + +.fa-egg { + --fa: "\f7fb"; + --fa--fa: "\f7fb\f7fb"; } + +.fa-house-medical-circle-xmark { + --fa: "\e513"; + --fa--fa: "\e513\e513"; } + +.fa-campground { + --fa: "\f6bb"; + --fa--fa: "\f6bb\f6bb"; } + +.fa-folder-plus { + --fa: "\f65e"; + --fa--fa: "\f65e\f65e"; } + +.fa-futbol { + --fa: "\f1e3"; + --fa--fa: "\f1e3\f1e3"; } + +.fa-futbol-ball { + --fa: "\f1e3"; + --fa--fa: "\f1e3\f1e3"; } + +.fa-soccer-ball { + --fa: "\f1e3"; + --fa--fa: "\f1e3\f1e3"; } + +.fa-paintbrush { + --fa: "\f1fc"; + --fa--fa: "\f1fc\f1fc"; } + +.fa-paint-brush { + --fa: "\f1fc"; + --fa--fa: "\f1fc\f1fc"; } + +.fa-lock { + --fa: "\f023"; + --fa--fa: "\f023\f023"; } + +.fa-gas-pump { + --fa: "\f52f"; + --fa--fa: "\f52f\f52f"; } + +.fa-hot-tub-person { + --fa: "\f593"; + --fa--fa: "\f593\f593"; } + +.fa-hot-tub { + --fa: "\f593"; + --fa--fa: "\f593\f593"; } + +.fa-map-location { + --fa: "\f59f"; + --fa--fa: "\f59f\f59f"; } + +.fa-map-marked { + --fa: "\f59f"; + --fa--fa: "\f59f\f59f"; } + +.fa-house-flood-water { + --fa: "\e50e"; + --fa--fa: "\e50e\e50e"; } + +.fa-tree { + --fa: "\f1bb"; + --fa--fa: "\f1bb\f1bb"; } + +.fa-bridge-lock { + --fa: "\e4cc"; + --fa--fa: "\e4cc\e4cc"; } + +.fa-sack-dollar { + --fa: "\f81d"; + --fa--fa: "\f81d\f81d"; } + +.fa-pen-to-square { + --fa: "\f044"; + --fa--fa: "\f044\f044"; } + +.fa-edit { + --fa: "\f044"; + --fa--fa: "\f044\f044"; } + +.fa-car-side { + --fa: "\f5e4"; + --fa--fa: "\f5e4\f5e4"; } + +.fa-share-nodes { + --fa: "\f1e0"; + --fa--fa: "\f1e0\f1e0"; } + +.fa-share-alt { + --fa: "\f1e0"; + --fa--fa: "\f1e0\f1e0"; } + +.fa-heart-circle-minus { + --fa: "\e4ff"; + --fa--fa: "\e4ff\e4ff"; } + +.fa-hourglass-half { + --fa: "\f252"; + --fa--fa: "\f252\f252"; } + +.fa-hourglass-2 { + --fa: "\f252"; + --fa--fa: "\f252\f252"; } + +.fa-microscope { + --fa: "\f610"; + --fa--fa: "\f610\f610"; } + +.fa-sink { + --fa: "\e06d"; + --fa--fa: "\e06d\e06d"; } + +.fa-bag-shopping { + --fa: "\f290"; + --fa--fa: "\f290\f290"; } + +.fa-shopping-bag { + --fa: "\f290"; + --fa--fa: "\f290\f290"; } + +.fa-arrow-down-z-a { + --fa: "\f881"; + --fa--fa: "\f881\f881"; } + +.fa-sort-alpha-desc { + --fa: "\f881"; + --fa--fa: "\f881\f881"; } + +.fa-sort-alpha-down-alt { + --fa: "\f881"; + --fa--fa: "\f881\f881"; } + +.fa-mitten { + --fa: "\f7b5"; + --fa--fa: "\f7b5\f7b5"; } + +.fa-person-rays { + --fa: "\e54d"; + --fa--fa: "\e54d\e54d"; } + +.fa-users { + --fa: "\f0c0"; + --fa--fa: "\f0c0\f0c0"; } + +.fa-eye-slash { + --fa: "\f070"; + --fa--fa: "\f070\f070"; } + +.fa-flask-vial { + --fa: "\e4f3"; + --fa--fa: "\e4f3\e4f3"; } + +.fa-hand { + --fa: "\f256"; + --fa--fa: "\f256\f256"; } + +.fa-hand-paper { + --fa: "\f256"; + --fa--fa: "\f256\f256"; } + +.fa-om { + --fa: "\f679"; + --fa--fa: "\f679\f679"; } + +.fa-worm { + --fa: "\e599"; + --fa--fa: "\e599\e599"; } + +.fa-house-circle-xmark { + --fa: "\e50b"; + --fa--fa: "\e50b\e50b"; } + +.fa-plug { + --fa: "\f1e6"; + --fa--fa: "\f1e6\f1e6"; } + +.fa-chevron-up { + --fa: "\f077"; + --fa--fa: "\f077\f077"; } + +.fa-hand-spock { + --fa: "\f259"; + --fa--fa: "\f259\f259"; } + +.fa-stopwatch { + --fa: "\f2f2"; + --fa--fa: "\f2f2\f2f2"; } + +.fa-face-kiss { + --fa: "\f596"; + --fa--fa: "\f596\f596"; } + +.fa-kiss { + --fa: "\f596"; + --fa--fa: "\f596\f596"; } + +.fa-bridge-circle-xmark { + --fa: "\e4cb"; + --fa--fa: "\e4cb\e4cb"; } + +.fa-face-grin-tongue { + --fa: "\f589"; + --fa--fa: "\f589\f589"; } + +.fa-grin-tongue { + --fa: "\f589"; + --fa--fa: "\f589\f589"; } + +.fa-chess-bishop { + --fa: "\f43a"; + --fa--fa: "\f43a\f43a"; } + +.fa-face-grin-wink { + --fa: "\f58c"; + --fa--fa: "\f58c\f58c"; } + +.fa-grin-wink { + --fa: "\f58c"; + --fa--fa: "\f58c\f58c"; } + +.fa-ear-deaf { + --fa: "\f2a4"; + --fa--fa: "\f2a4\f2a4"; } + +.fa-deaf { + --fa: "\f2a4"; + --fa--fa: "\f2a4\f2a4"; } + +.fa-deafness { + --fa: "\f2a4"; + --fa--fa: "\f2a4\f2a4"; } + +.fa-hard-of-hearing { + --fa: "\f2a4"; + --fa--fa: "\f2a4\f2a4"; } + +.fa-road-circle-check { + --fa: "\e564"; + --fa--fa: "\e564\e564"; } + +.fa-dice-five { + --fa: "\f523"; + --fa--fa: "\f523\f523"; } + +.fa-square-rss { + --fa: "\f143"; + --fa--fa: "\f143\f143"; } + +.fa-rss-square { + --fa: "\f143"; + --fa--fa: "\f143\f143"; } + +.fa-land-mine-on { + --fa: "\e51b"; + --fa--fa: "\e51b\e51b"; } + +.fa-i-cursor { + --fa: "\f246"; + --fa--fa: "\f246\f246"; } + +.fa-stamp { + --fa: "\f5bf"; + --fa--fa: "\f5bf\f5bf"; } + +.fa-stairs { + --fa: "\e289"; + --fa--fa: "\e289\e289"; } + +.fa-i { + --fa: "\49"; + --fa--fa: "\49\49"; } + +.fa-hryvnia-sign { + --fa: "\f6f2"; + --fa--fa: "\f6f2\f6f2"; } + +.fa-hryvnia { + --fa: "\f6f2"; + --fa--fa: "\f6f2\f6f2"; } + +.fa-pills { + --fa: "\f484"; + --fa--fa: "\f484\f484"; } + +.fa-face-grin-wide { + --fa: "\f581"; + --fa--fa: "\f581\f581"; } + +.fa-grin-alt { + --fa: "\f581"; + --fa--fa: "\f581\f581"; } + +.fa-tooth { + --fa: "\f5c9"; + --fa--fa: "\f5c9\f5c9"; } + +.fa-v { + --fa: "\56"; + --fa--fa: "\56\56"; } + +.fa-bangladeshi-taka-sign { + --fa: "\e2e6"; + --fa--fa: "\e2e6\e2e6"; } + +.fa-bicycle { + --fa: "\f206"; + --fa--fa: "\f206\f206"; } + +.fa-staff-snake { + --fa: "\e579"; + --fa--fa: "\e579\e579"; } + +.fa-rod-asclepius { + --fa: "\e579"; + --fa--fa: "\e579\e579"; } + +.fa-rod-snake { + --fa: "\e579"; + --fa--fa: "\e579\e579"; } + +.fa-staff-aesculapius { + --fa: "\e579"; + --fa--fa: "\e579\e579"; } + +.fa-head-side-cough-slash { + --fa: "\e062"; + --fa--fa: "\e062\e062"; } + +.fa-truck-medical { + --fa: "\f0f9"; + --fa--fa: "\f0f9\f0f9"; } + +.fa-ambulance { + --fa: "\f0f9"; + --fa--fa: "\f0f9\f0f9"; } + +.fa-wheat-awn-circle-exclamation { + --fa: "\e598"; + --fa--fa: "\e598\e598"; } + +.fa-snowman { + --fa: "\f7d0"; + --fa--fa: "\f7d0\f7d0"; } + +.fa-mortar-pestle { + --fa: "\f5a7"; + --fa--fa: "\f5a7\f5a7"; } + +.fa-road-barrier { + --fa: "\e562"; + --fa--fa: "\e562\e562"; } + +.fa-school { + --fa: "\f549"; + --fa--fa: "\f549\f549"; } + +.fa-igloo { + --fa: "\f7ae"; + --fa--fa: "\f7ae\f7ae"; } + +.fa-joint { + --fa: "\f595"; + --fa--fa: "\f595\f595"; } + +.fa-angle-right { + --fa: "\f105"; + --fa--fa: "\f105\f105"; } + +.fa-horse { + --fa: "\f6f0"; + --fa--fa: "\f6f0\f6f0"; } + +.fa-q { + --fa: "\51"; + --fa--fa: "\51\51"; } + +.fa-g { + --fa: "\47"; + --fa--fa: "\47\47"; } + +.fa-notes-medical { + --fa: "\f481"; + --fa--fa: "\f481\f481"; } + +.fa-temperature-half { + --fa: "\f2c9"; + --fa--fa: "\f2c9\f2c9"; } + +.fa-temperature-2 { + --fa: "\f2c9"; + --fa--fa: "\f2c9\f2c9"; } + +.fa-thermometer-2 { + --fa: "\f2c9"; + --fa--fa: "\f2c9\f2c9"; } + +.fa-thermometer-half { + --fa: "\f2c9"; + --fa--fa: "\f2c9\f2c9"; } + +.fa-dong-sign { + --fa: "\e169"; + --fa--fa: "\e169\e169"; } + +.fa-capsules { + --fa: "\f46b"; + --fa--fa: "\f46b\f46b"; } + +.fa-poo-storm { + --fa: "\f75a"; + --fa--fa: "\f75a\f75a"; } + +.fa-poo-bolt { + --fa: "\f75a"; + --fa--fa: "\f75a\f75a"; } + +.fa-face-frown-open { + --fa: "\f57a"; + --fa--fa: "\f57a\f57a"; } + +.fa-frown-open { + --fa: "\f57a"; + --fa--fa: "\f57a\f57a"; } + +.fa-hand-point-up { + --fa: "\f0a6"; + --fa--fa: "\f0a6\f0a6"; } + +.fa-money-bill { + --fa: "\f0d6"; + --fa--fa: "\f0d6\f0d6"; } + +.fa-bookmark { + --fa: "\f02e"; + --fa--fa: "\f02e\f02e"; } + +.fa-align-justify { + --fa: "\f039"; + --fa--fa: "\f039\f039"; } + +.fa-umbrella-beach { + --fa: "\f5ca"; + --fa--fa: "\f5ca\f5ca"; } + +.fa-helmet-un { + --fa: "\e503"; + --fa--fa: "\e503\e503"; } + +.fa-bullseye { + --fa: "\f140"; + --fa--fa: "\f140\f140"; } + +.fa-bacon { + --fa: "\f7e5"; + --fa--fa: "\f7e5\f7e5"; } + +.fa-hand-point-down { + --fa: "\f0a7"; + --fa--fa: "\f0a7\f0a7"; } + +.fa-arrow-up-from-bracket { + --fa: "\e09a"; + --fa--fa: "\e09a\e09a"; } + +.fa-folder { + --fa: "\f07b"; + --fa--fa: "\f07b\f07b"; } + +.fa-folder-blank { + --fa: "\f07b"; + --fa--fa: "\f07b\f07b"; } + +.fa-file-waveform { + --fa: "\f478"; + --fa--fa: "\f478\f478"; } + +.fa-file-medical-alt { + --fa: "\f478"; + --fa--fa: "\f478\f478"; } + +.fa-radiation { + --fa: "\f7b9"; + --fa--fa: "\f7b9\f7b9"; } + +.fa-chart-simple { + --fa: "\e473"; + --fa--fa: "\e473\e473"; } + +.fa-mars-stroke { + --fa: "\f229"; + --fa--fa: "\f229\f229"; } + +.fa-vial { + --fa: "\f492"; + --fa--fa: "\f492\f492"; } + +.fa-gauge { + --fa: "\f624"; + --fa--fa: "\f624\f624"; } + +.fa-dashboard { + --fa: "\f624"; + --fa--fa: "\f624\f624"; } + +.fa-gauge-med { + --fa: "\f624"; + --fa--fa: "\f624\f624"; } + +.fa-tachometer-alt-average { + --fa: "\f624"; + --fa--fa: "\f624\f624"; } + +.fa-wand-magic-sparkles { + --fa: "\e2ca"; + --fa--fa: "\e2ca\e2ca"; } + +.fa-magic-wand-sparkles { + --fa: "\e2ca"; + --fa--fa: "\e2ca\e2ca"; } + +.fa-e { + --fa: "\45"; + --fa--fa: "\45\45"; } + +.fa-pen-clip { + --fa: "\f305"; + --fa--fa: "\f305\f305"; } + +.fa-pen-alt { + --fa: "\f305"; + --fa--fa: "\f305\f305"; } + +.fa-bridge-circle-exclamation { + --fa: "\e4ca"; + --fa--fa: "\e4ca\e4ca"; } + +.fa-user { + --fa: "\f007"; + --fa--fa: "\f007\f007"; } + +.fa-school-circle-check { + --fa: "\e56b"; + --fa--fa: "\e56b\e56b"; } + +.fa-dumpster { + --fa: "\f793"; + --fa--fa: "\f793\f793"; } + +.fa-van-shuttle { + --fa: "\f5b6"; + --fa--fa: "\f5b6\f5b6"; } + +.fa-shuttle-van { + --fa: "\f5b6"; + --fa--fa: "\f5b6\f5b6"; } + +.fa-building-user { + --fa: "\e4da"; + --fa--fa: "\e4da\e4da"; } + +.fa-square-caret-left { + --fa: "\f191"; + --fa--fa: "\f191\f191"; } + +.fa-caret-square-left { + --fa: "\f191"; + --fa--fa: "\f191\f191"; } + +.fa-highlighter { + --fa: "\f591"; + --fa--fa: "\f591\f591"; } + +.fa-key { + --fa: "\f084"; + --fa--fa: "\f084\f084"; } + +.fa-bullhorn { + --fa: "\f0a1"; + --fa--fa: "\f0a1\f0a1"; } + +.fa-globe { + --fa: "\f0ac"; + --fa--fa: "\f0ac\f0ac"; } + +.fa-synagogue { + --fa: "\f69b"; + --fa--fa: "\f69b\f69b"; } + +.fa-person-half-dress { + --fa: "\e548"; + --fa--fa: "\e548\e548"; } + +.fa-road-bridge { + --fa: "\e563"; + --fa--fa: "\e563\e563"; } + +.fa-location-arrow { + --fa: "\f124"; + --fa--fa: "\f124\f124"; } + +.fa-c { + --fa: "\43"; + --fa--fa: "\43\43"; } + +.fa-tablet-button { + --fa: "\f10a"; + --fa--fa: "\f10a\f10a"; } + +.fa-building-lock { + --fa: "\e4d6"; + --fa--fa: "\e4d6\e4d6"; } + +.fa-pizza-slice { + --fa: "\f818"; + --fa--fa: "\f818\f818"; } + +.fa-money-bill-wave { + --fa: "\f53a"; + --fa--fa: "\f53a\f53a"; } + +.fa-chart-area { + --fa: "\f1fe"; + --fa--fa: "\f1fe\f1fe"; } + +.fa-area-chart { + --fa: "\f1fe"; + --fa--fa: "\f1fe\f1fe"; } + +.fa-house-flag { + --fa: "\e50d"; + --fa--fa: "\e50d\e50d"; } + +.fa-person-circle-minus { + --fa: "\e540"; + --fa--fa: "\e540\e540"; } + +.fa-ban { + --fa: "\f05e"; + --fa--fa: "\f05e\f05e"; } + +.fa-cancel { + --fa: "\f05e"; + --fa--fa: "\f05e\f05e"; } + +.fa-camera-rotate { + --fa: "\e0d8"; + --fa--fa: "\e0d8\e0d8"; } + +.fa-spray-can-sparkles { + --fa: "\f5d0"; + --fa--fa: "\f5d0\f5d0"; } + +.fa-air-freshener { + --fa: "\f5d0"; + --fa--fa: "\f5d0\f5d0"; } + +.fa-star { + --fa: "\f005"; + --fa--fa: "\f005\f005"; } + +.fa-repeat { + --fa: "\f363"; + --fa--fa: "\f363\f363"; } + +.fa-cross { + --fa: "\f654"; + --fa--fa: "\f654\f654"; } + +.fa-box { + --fa: "\f466"; + --fa--fa: "\f466\f466"; } + +.fa-venus-mars { + --fa: "\f228"; + --fa--fa: "\f228\f228"; } + +.fa-arrow-pointer { + --fa: "\f245"; + --fa--fa: "\f245\f245"; } + +.fa-mouse-pointer { + --fa: "\f245"; + --fa--fa: "\f245\f245"; } + +.fa-maximize { + --fa: "\f31e"; + --fa--fa: "\f31e\f31e"; } + +.fa-expand-arrows-alt { + --fa: "\f31e"; + --fa--fa: "\f31e\f31e"; } + +.fa-charging-station { + --fa: "\f5e7"; + --fa--fa: "\f5e7\f5e7"; } + +.fa-shapes { + --fa: "\f61f"; + --fa--fa: "\f61f\f61f"; } + +.fa-triangle-circle-square { + --fa: "\f61f"; + --fa--fa: "\f61f\f61f"; } + +.fa-shuffle { + --fa: "\f074"; + --fa--fa: "\f074\f074"; } + +.fa-random { + --fa: "\f074"; + --fa--fa: "\f074\f074"; } + +.fa-person-running { + --fa: "\f70c"; + --fa--fa: "\f70c\f70c"; } + +.fa-running { + --fa: "\f70c"; + --fa--fa: "\f70c\f70c"; } + +.fa-mobile-retro { + --fa: "\e527"; + --fa--fa: "\e527\e527"; } + +.fa-grip-lines-vertical { + --fa: "\f7a5"; + --fa--fa: "\f7a5\f7a5"; } + +.fa-spider { + --fa: "\f717"; + --fa--fa: "\f717\f717"; } + +.fa-hands-bound { + --fa: "\e4f9"; + --fa--fa: "\e4f9\e4f9"; } + +.fa-file-invoice-dollar { + --fa: "\f571"; + --fa--fa: "\f571\f571"; } + +.fa-plane-circle-exclamation { + --fa: "\e556"; + --fa--fa: "\e556\e556"; } + +.fa-x-ray { + --fa: "\f497"; + --fa--fa: "\f497\f497"; } + +.fa-spell-check { + --fa: "\f891"; + --fa--fa: "\f891\f891"; } + +.fa-slash { + --fa: "\f715"; + --fa--fa: "\f715\f715"; } + +.fa-computer-mouse { + --fa: "\f8cc"; + --fa--fa: "\f8cc\f8cc"; } + +.fa-mouse { + --fa: "\f8cc"; + --fa--fa: "\f8cc\f8cc"; } + +.fa-arrow-right-to-bracket { + --fa: "\f090"; + --fa--fa: "\f090\f090"; } + +.fa-sign-in { + --fa: "\f090"; + --fa--fa: "\f090\f090"; } + +.fa-shop-slash { + --fa: "\e070"; + --fa--fa: "\e070\e070"; } + +.fa-store-alt-slash { + --fa: "\e070"; + --fa--fa: "\e070\e070"; } + +.fa-server { + --fa: "\f233"; + --fa--fa: "\f233\f233"; } + +.fa-virus-covid-slash { + --fa: "\e4a9"; + --fa--fa: "\e4a9\e4a9"; } + +.fa-shop-lock { + --fa: "\e4a5"; + --fa--fa: "\e4a5\e4a5"; } + +.fa-hourglass-start { + --fa: "\f251"; + --fa--fa: "\f251\f251"; } + +.fa-hourglass-1 { + --fa: "\f251"; + --fa--fa: "\f251\f251"; } + +.fa-blender-phone { + --fa: "\f6b6"; + --fa--fa: "\f6b6\f6b6"; } + +.fa-building-wheat { + --fa: "\e4db"; + --fa--fa: "\e4db\e4db"; } + +.fa-person-breastfeeding { + --fa: "\e53a"; + --fa--fa: "\e53a\e53a"; } + +.fa-right-to-bracket { + --fa: "\f2f6"; + --fa--fa: "\f2f6\f2f6"; } + +.fa-sign-in-alt { + --fa: "\f2f6"; + --fa--fa: "\f2f6\f2f6"; } + +.fa-venus { + --fa: "\f221"; + --fa--fa: "\f221\f221"; } + +.fa-passport { + --fa: "\f5ab"; + --fa--fa: "\f5ab\f5ab"; } + +.fa-thumbtack-slash { + --fa: "\e68f"; + --fa--fa: "\e68f\e68f"; } + +.fa-thumb-tack-slash { + --fa: "\e68f"; + --fa--fa: "\e68f\e68f"; } + +.fa-heart-pulse { + --fa: "\f21e"; + --fa--fa: "\f21e\f21e"; } + +.fa-heartbeat { + --fa: "\f21e"; + --fa--fa: "\f21e\f21e"; } + +.fa-people-carry-box { + --fa: "\f4ce"; + --fa--fa: "\f4ce\f4ce"; } + +.fa-people-carry { + --fa: "\f4ce"; + --fa--fa: "\f4ce\f4ce"; } + +.fa-temperature-high { + --fa: "\f769"; + --fa--fa: "\f769\f769"; } + +.fa-microchip { + --fa: "\f2db"; + --fa--fa: "\f2db\f2db"; } + +.fa-crown { + --fa: "\f521"; + --fa--fa: "\f521\f521"; } + +.fa-weight-hanging { + --fa: "\f5cd"; + --fa--fa: "\f5cd\f5cd"; } + +.fa-xmarks-lines { + --fa: "\e59a"; + --fa--fa: "\e59a\e59a"; } + +.fa-file-prescription { + --fa: "\f572"; + --fa--fa: "\f572\f572"; } + +.fa-weight-scale { + --fa: "\f496"; + --fa--fa: "\f496\f496"; } + +.fa-weight { + --fa: "\f496"; + --fa--fa: "\f496\f496"; } + +.fa-user-group { + --fa: "\f500"; + --fa--fa: "\f500\f500"; } + +.fa-user-friends { + --fa: "\f500"; + --fa--fa: "\f500\f500"; } + +.fa-arrow-up-a-z { + --fa: "\f15e"; + --fa--fa: "\f15e\f15e"; } + +.fa-sort-alpha-up { + --fa: "\f15e"; + --fa--fa: "\f15e\f15e"; } + +.fa-chess-knight { + --fa: "\f441"; + --fa--fa: "\f441\f441"; } + +.fa-face-laugh-squint { + --fa: "\f59b"; + --fa--fa: "\f59b\f59b"; } + +.fa-laugh-squint { + --fa: "\f59b"; + --fa--fa: "\f59b\f59b"; } + +.fa-wheelchair { + --fa: "\f193"; + --fa--fa: "\f193\f193"; } + +.fa-circle-arrow-up { + --fa: "\f0aa"; + --fa--fa: "\f0aa\f0aa"; } + +.fa-arrow-circle-up { + --fa: "\f0aa"; + --fa--fa: "\f0aa\f0aa"; } + +.fa-toggle-on { + --fa: "\f205"; + --fa--fa: "\f205\f205"; } + +.fa-person-walking { + --fa: "\f554"; + --fa--fa: "\f554\f554"; } + +.fa-walking { + --fa: "\f554"; + --fa--fa: "\f554\f554"; } + +.fa-l { + --fa: "\4c"; + --fa--fa: "\4c\4c"; } + +.fa-fire { + --fa: "\f06d"; + --fa--fa: "\f06d\f06d"; } + +.fa-bed-pulse { + --fa: "\f487"; + --fa--fa: "\f487\f487"; } + +.fa-procedures { + --fa: "\f487"; + --fa--fa: "\f487\f487"; } + +.fa-shuttle-space { + --fa: "\f197"; + --fa--fa: "\f197\f197"; } + +.fa-space-shuttle { + --fa: "\f197"; + --fa--fa: "\f197\f197"; } + +.fa-face-laugh { + --fa: "\f599"; + --fa--fa: "\f599\f599"; } + +.fa-laugh { + --fa: "\f599"; + --fa--fa: "\f599\f599"; } + +.fa-folder-open { + --fa: "\f07c"; + --fa--fa: "\f07c\f07c"; } + +.fa-heart-circle-plus { + --fa: "\e500"; + --fa--fa: "\e500\e500"; } + +.fa-code-fork { + --fa: "\e13b"; + --fa--fa: "\e13b\e13b"; } + +.fa-city { + --fa: "\f64f"; + --fa--fa: "\f64f\f64f"; } + +.fa-microphone-lines { + --fa: "\f3c9"; + --fa--fa: "\f3c9\f3c9"; } + +.fa-microphone-alt { + --fa: "\f3c9"; + --fa--fa: "\f3c9\f3c9"; } + +.fa-pepper-hot { + --fa: "\f816"; + --fa--fa: "\f816\f816"; } + +.fa-unlock { + --fa: "\f09c"; + --fa--fa: "\f09c\f09c"; } + +.fa-colon-sign { + --fa: "\e140"; + --fa--fa: "\e140\e140"; } + +.fa-headset { + --fa: "\f590"; + --fa--fa: "\f590\f590"; } + +.fa-store-slash { + --fa: "\e071"; + --fa--fa: "\e071\e071"; } + +.fa-road-circle-xmark { + --fa: "\e566"; + --fa--fa: "\e566\e566"; } + +.fa-user-minus { + --fa: "\f503"; + --fa--fa: "\f503\f503"; } + +.fa-mars-stroke-up { + --fa: "\f22a"; + --fa--fa: "\f22a\f22a"; } + +.fa-mars-stroke-v { + --fa: "\f22a"; + --fa--fa: "\f22a\f22a"; } + +.fa-champagne-glasses { + --fa: "\f79f"; + --fa--fa: "\f79f\f79f"; } + +.fa-glass-cheers { + --fa: "\f79f"; + --fa--fa: "\f79f\f79f"; } + +.fa-clipboard { + --fa: "\f328"; + --fa--fa: "\f328\f328"; } + +.fa-house-circle-exclamation { + --fa: "\e50a"; + --fa--fa: "\e50a\e50a"; } + +.fa-file-arrow-up { + --fa: "\f574"; + --fa--fa: "\f574\f574"; } + +.fa-file-upload { + --fa: "\f574"; + --fa--fa: "\f574\f574"; } + +.fa-wifi { + --fa: "\f1eb"; + --fa--fa: "\f1eb\f1eb"; } + +.fa-wifi-3 { + --fa: "\f1eb"; + --fa--fa: "\f1eb\f1eb"; } + +.fa-wifi-strong { + --fa: "\f1eb"; + --fa--fa: "\f1eb\f1eb"; } + +.fa-bath { + --fa: "\f2cd"; + --fa--fa: "\f2cd\f2cd"; } + +.fa-bathtub { + --fa: "\f2cd"; + --fa--fa: "\f2cd\f2cd"; } + +.fa-underline { + --fa: "\f0cd"; + --fa--fa: "\f0cd\f0cd"; } + +.fa-user-pen { + --fa: "\f4ff"; + --fa--fa: "\f4ff\f4ff"; } + +.fa-user-edit { + --fa: "\f4ff"; + --fa--fa: "\f4ff\f4ff"; } + +.fa-signature { + --fa: "\f5b7"; + --fa--fa: "\f5b7\f5b7"; } + +.fa-stroopwafel { + --fa: "\f551"; + --fa--fa: "\f551\f551"; } + +.fa-bold { + --fa: "\f032"; + --fa--fa: "\f032\f032"; } + +.fa-anchor-lock { + --fa: "\e4ad"; + --fa--fa: "\e4ad\e4ad"; } + +.fa-building-ngo { + --fa: "\e4d7"; + --fa--fa: "\e4d7\e4d7"; } + +.fa-manat-sign { + --fa: "\e1d5"; + --fa--fa: "\e1d5\e1d5"; } + +.fa-not-equal { + --fa: "\f53e"; + --fa--fa: "\f53e\f53e"; } + +.fa-border-top-left { + --fa: "\f853"; + --fa--fa: "\f853\f853"; } + +.fa-border-style { + --fa: "\f853"; + --fa--fa: "\f853\f853"; } + +.fa-map-location-dot { + --fa: "\f5a0"; + --fa--fa: "\f5a0\f5a0"; } + +.fa-map-marked-alt { + --fa: "\f5a0"; + --fa--fa: "\f5a0\f5a0"; } + +.fa-jedi { + --fa: "\f669"; + --fa--fa: "\f669\f669"; } + +.fa-square-poll-vertical { + --fa: "\f681"; + --fa--fa: "\f681\f681"; } + +.fa-poll { + --fa: "\f681"; + --fa--fa: "\f681\f681"; } + +.fa-mug-hot { + --fa: "\f7b6"; + --fa--fa: "\f7b6\f7b6"; } + +.fa-car-battery { + --fa: "\f5df"; + --fa--fa: "\f5df\f5df"; } + +.fa-battery-car { + --fa: "\f5df"; + --fa--fa: "\f5df\f5df"; } + +.fa-gift { + --fa: "\f06b"; + --fa--fa: "\f06b\f06b"; } + +.fa-dice-two { + --fa: "\f528"; + --fa--fa: "\f528\f528"; } + +.fa-chess-queen { + --fa: "\f445"; + --fa--fa: "\f445\f445"; } + +.fa-glasses { + --fa: "\f530"; + --fa--fa: "\f530\f530"; } + +.fa-chess-board { + --fa: "\f43c"; + --fa--fa: "\f43c\f43c"; } + +.fa-building-circle-check { + --fa: "\e4d2"; + --fa--fa: "\e4d2\e4d2"; } + +.fa-person-chalkboard { + --fa: "\e53d"; + --fa--fa: "\e53d\e53d"; } + +.fa-mars-stroke-right { + --fa: "\f22b"; + --fa--fa: "\f22b\f22b"; } + +.fa-mars-stroke-h { + --fa: "\f22b"; + --fa--fa: "\f22b\f22b"; } + +.fa-hand-back-fist { + --fa: "\f255"; + --fa--fa: "\f255\f255"; } + +.fa-hand-rock { + --fa: "\f255"; + --fa--fa: "\f255\f255"; } + +.fa-square-caret-up { + --fa: "\f151"; + --fa--fa: "\f151\f151"; } + +.fa-caret-square-up { + --fa: "\f151"; + --fa--fa: "\f151\f151"; } + +.fa-cloud-showers-water { + --fa: "\e4e4"; + --fa--fa: "\e4e4\e4e4"; } + +.fa-chart-bar { + --fa: "\f080"; + --fa--fa: "\f080\f080"; } + +.fa-bar-chart { + --fa: "\f080"; + --fa--fa: "\f080\f080"; } + +.fa-hands-bubbles { + --fa: "\e05e"; + --fa--fa: "\e05e\e05e"; } + +.fa-hands-wash { + --fa: "\e05e"; + --fa--fa: "\e05e\e05e"; } + +.fa-less-than-equal { + --fa: "\f537"; + --fa--fa: "\f537\f537"; } + +.fa-train { + --fa: "\f238"; + --fa--fa: "\f238\f238"; } + +.fa-eye-low-vision { + --fa: "\f2a8"; + --fa--fa: "\f2a8\f2a8"; } + +.fa-low-vision { + --fa: "\f2a8"; + --fa--fa: "\f2a8\f2a8"; } + +.fa-crow { + --fa: "\f520"; + --fa--fa: "\f520\f520"; } + +.fa-sailboat { + --fa: "\e445"; + --fa--fa: "\e445\e445"; } + +.fa-window-restore { + --fa: "\f2d2"; + --fa--fa: "\f2d2\f2d2"; } + +.fa-square-plus { + --fa: "\f0fe"; + --fa--fa: "\f0fe\f0fe"; } + +.fa-plus-square { + --fa: "\f0fe"; + --fa--fa: "\f0fe\f0fe"; } + +.fa-torii-gate { + --fa: "\f6a1"; + --fa--fa: "\f6a1\f6a1"; } + +.fa-frog { + --fa: "\f52e"; + --fa--fa: "\f52e\f52e"; } + +.fa-bucket { + --fa: "\e4cf"; + --fa--fa: "\e4cf\e4cf"; } + +.fa-image { + --fa: "\f03e"; + --fa--fa: "\f03e\f03e"; } + +.fa-microphone { + --fa: "\f130"; + --fa--fa: "\f130\f130"; } + +.fa-cow { + --fa: "\f6c8"; + --fa--fa: "\f6c8\f6c8"; } + +.fa-caret-up { + --fa: "\f0d8"; + --fa--fa: "\f0d8\f0d8"; } + +.fa-screwdriver { + --fa: "\f54a"; + --fa--fa: "\f54a\f54a"; } + +.fa-folder-closed { + --fa: "\e185"; + --fa--fa: "\e185\e185"; } + +.fa-house-tsunami { + --fa: "\e515"; + --fa--fa: "\e515\e515"; } + +.fa-square-nfi { + --fa: "\e576"; + --fa--fa: "\e576\e576"; } + +.fa-arrow-up-from-ground-water { + --fa: "\e4b5"; + --fa--fa: "\e4b5\e4b5"; } + +.fa-martini-glass { + --fa: "\f57b"; + --fa--fa: "\f57b\f57b"; } + +.fa-glass-martini-alt { + --fa: "\f57b"; + --fa--fa: "\f57b\f57b"; } + +.fa-square-binary { + --fa: "\e69b"; + --fa--fa: "\e69b\e69b"; } + +.fa-rotate-left { + --fa: "\f2ea"; + --fa--fa: "\f2ea\f2ea"; } + +.fa-rotate-back { + --fa: "\f2ea"; + --fa--fa: "\f2ea\f2ea"; } + +.fa-rotate-backward { + --fa: "\f2ea"; + --fa--fa: "\f2ea\f2ea"; } + +.fa-undo-alt { + --fa: "\f2ea"; + --fa--fa: "\f2ea\f2ea"; } + +.fa-table-columns { + --fa: "\f0db"; + --fa--fa: "\f0db\f0db"; } + +.fa-columns { + --fa: "\f0db"; + --fa--fa: "\f0db\f0db"; } + +.fa-lemon { + --fa: "\f094"; + --fa--fa: "\f094\f094"; } + +.fa-head-side-mask { + --fa: "\e063"; + --fa--fa: "\e063\e063"; } + +.fa-handshake { + --fa: "\f2b5"; + --fa--fa: "\f2b5\f2b5"; } + +.fa-gem { + --fa: "\f3a5"; + --fa--fa: "\f3a5\f3a5"; } + +.fa-dolly { + --fa: "\f472"; + --fa--fa: "\f472\f472"; } + +.fa-dolly-box { + --fa: "\f472"; + --fa--fa: "\f472\f472"; } + +.fa-smoking { + --fa: "\f48d"; + --fa--fa: "\f48d\f48d"; } + +.fa-minimize { + --fa: "\f78c"; + --fa--fa: "\f78c\f78c"; } + +.fa-compress-arrows-alt { + --fa: "\f78c"; + --fa--fa: "\f78c\f78c"; } + +.fa-monument { + --fa: "\f5a6"; + --fa--fa: "\f5a6\f5a6"; } + +.fa-snowplow { + --fa: "\f7d2"; + --fa--fa: "\f7d2\f7d2"; } + +.fa-angles-right { + --fa: "\f101"; + --fa--fa: "\f101\f101"; } + +.fa-angle-double-right { + --fa: "\f101"; + --fa--fa: "\f101\f101"; } + +.fa-cannabis { + --fa: "\f55f"; + --fa--fa: "\f55f\f55f"; } + +.fa-circle-play { + --fa: "\f144"; + --fa--fa: "\f144\f144"; } + +.fa-play-circle { + --fa: "\f144"; + --fa--fa: "\f144\f144"; } + +.fa-tablets { + --fa: "\f490"; + --fa--fa: "\f490\f490"; } + +.fa-ethernet { + --fa: "\f796"; + --fa--fa: "\f796\f796"; } + +.fa-euro-sign { + --fa: "\f153"; + --fa--fa: "\f153\f153"; } + +.fa-eur { + --fa: "\f153"; + --fa--fa: "\f153\f153"; } + +.fa-euro { + --fa: "\f153"; + --fa--fa: "\f153\f153"; } + +.fa-chair { + --fa: "\f6c0"; + --fa--fa: "\f6c0\f6c0"; } + +.fa-circle-check { + --fa: "\f058"; + --fa--fa: "\f058\f058"; } + +.fa-check-circle { + --fa: "\f058"; + --fa--fa: "\f058\f058"; } + +.fa-circle-stop { + --fa: "\f28d"; + --fa--fa: "\f28d\f28d"; } + +.fa-stop-circle { + --fa: "\f28d"; + --fa--fa: "\f28d\f28d"; } + +.fa-compass-drafting { + --fa: "\f568"; + --fa--fa: "\f568\f568"; } + +.fa-drafting-compass { + --fa: "\f568"; + --fa--fa: "\f568\f568"; } + +.fa-plate-wheat { + --fa: "\e55a"; + --fa--fa: "\e55a\e55a"; } + +.fa-icicles { + --fa: "\f7ad"; + --fa--fa: "\f7ad\f7ad"; } + +.fa-person-shelter { + --fa: "\e54f"; + --fa--fa: "\e54f\e54f"; } + +.fa-neuter { + --fa: "\f22c"; + --fa--fa: "\f22c\f22c"; } + +.fa-id-badge { + --fa: "\f2c1"; + --fa--fa: "\f2c1\f2c1"; } + +.fa-marker { + --fa: "\f5a1"; + --fa--fa: "\f5a1\f5a1"; } + +.fa-face-laugh-beam { + --fa: "\f59a"; + --fa--fa: "\f59a\f59a"; } + +.fa-laugh-beam { + --fa: "\f59a"; + --fa--fa: "\f59a\f59a"; } + +.fa-helicopter-symbol { + --fa: "\e502"; + --fa--fa: "\e502\e502"; } + +.fa-universal-access { + --fa: "\f29a"; + --fa--fa: "\f29a\f29a"; } + +.fa-circle-chevron-up { + --fa: "\f139"; + --fa--fa: "\f139\f139"; } + +.fa-chevron-circle-up { + --fa: "\f139"; + --fa--fa: "\f139\f139"; } + +.fa-lari-sign { + --fa: "\e1c8"; + --fa--fa: "\e1c8\e1c8"; } + +.fa-volcano { + --fa: "\f770"; + --fa--fa: "\f770\f770"; } + +.fa-person-walking-dashed-line-arrow-right { + --fa: "\e553"; + --fa--fa: "\e553\e553"; } + +.fa-sterling-sign { + --fa: "\f154"; + --fa--fa: "\f154\f154"; } + +.fa-gbp { + --fa: "\f154"; + --fa--fa: "\f154\f154"; } + +.fa-pound-sign { + --fa: "\f154"; + --fa--fa: "\f154\f154"; } + +.fa-viruses { + --fa: "\e076"; + --fa--fa: "\e076\e076"; } + +.fa-square-person-confined { + --fa: "\e577"; + --fa--fa: "\e577\e577"; } + +.fa-user-tie { + --fa: "\f508"; + --fa--fa: "\f508\f508"; } + +.fa-arrow-down-long { + --fa: "\f175"; + --fa--fa: "\f175\f175"; } + +.fa-long-arrow-down { + --fa: "\f175"; + --fa--fa: "\f175\f175"; } + +.fa-tent-arrow-down-to-line { + --fa: "\e57e"; + --fa--fa: "\e57e\e57e"; } + +.fa-certificate { + --fa: "\f0a3"; + --fa--fa: "\f0a3\f0a3"; } + +.fa-reply-all { + --fa: "\f122"; + --fa--fa: "\f122\f122"; } + +.fa-mail-reply-all { + --fa: "\f122"; + --fa--fa: "\f122\f122"; } + +.fa-suitcase { + --fa: "\f0f2"; + --fa--fa: "\f0f2\f0f2"; } + +.fa-person-skating { + --fa: "\f7c5"; + --fa--fa: "\f7c5\f7c5"; } + +.fa-skating { + --fa: "\f7c5"; + --fa--fa: "\f7c5\f7c5"; } + +.fa-filter-circle-dollar { + --fa: "\f662"; + --fa--fa: "\f662\f662"; } + +.fa-funnel-dollar { + --fa: "\f662"; + --fa--fa: "\f662\f662"; } + +.fa-camera-retro { + --fa: "\f083"; + --fa--fa: "\f083\f083"; } + +.fa-circle-arrow-down { + --fa: "\f0ab"; + --fa--fa: "\f0ab\f0ab"; } + +.fa-arrow-circle-down { + --fa: "\f0ab"; + --fa--fa: "\f0ab\f0ab"; } + +.fa-file-import { + --fa: "\f56f"; + --fa--fa: "\f56f\f56f"; } + +.fa-arrow-right-to-file { + --fa: "\f56f"; + --fa--fa: "\f56f\f56f"; } + +.fa-square-arrow-up-right { + --fa: "\f14c"; + --fa--fa: "\f14c\f14c"; } + +.fa-external-link-square { + --fa: "\f14c"; + --fa--fa: "\f14c\f14c"; } + +.fa-box-open { + --fa: "\f49e"; + --fa--fa: "\f49e\f49e"; } + +.fa-scroll { + --fa: "\f70e"; + --fa--fa: "\f70e\f70e"; } + +.fa-spa { + --fa: "\f5bb"; + --fa--fa: "\f5bb\f5bb"; } + +.fa-location-pin-lock { + --fa: "\e51f"; + --fa--fa: "\e51f\e51f"; } + +.fa-pause { + --fa: "\f04c"; + --fa--fa: "\f04c\f04c"; } + +.fa-hill-avalanche { + --fa: "\e507"; + --fa--fa: "\e507\e507"; } + +.fa-temperature-empty { + --fa: "\f2cb"; + --fa--fa: "\f2cb\f2cb"; } + +.fa-temperature-0 { + --fa: "\f2cb"; + --fa--fa: "\f2cb\f2cb"; } + +.fa-thermometer-0 { + --fa: "\f2cb"; + --fa--fa: "\f2cb\f2cb"; } + +.fa-thermometer-empty { + --fa: "\f2cb"; + --fa--fa: "\f2cb\f2cb"; } + +.fa-bomb { + --fa: "\f1e2"; + --fa--fa: "\f1e2\f1e2"; } + +.fa-registered { + --fa: "\f25d"; + --fa--fa: "\f25d\f25d"; } + +.fa-address-card { + --fa: "\f2bb"; + --fa--fa: "\f2bb\f2bb"; } + +.fa-contact-card { + --fa: "\f2bb"; + --fa--fa: "\f2bb\f2bb"; } + +.fa-vcard { + --fa: "\f2bb"; + --fa--fa: "\f2bb\f2bb"; } + +.fa-scale-unbalanced-flip { + --fa: "\f516"; + --fa--fa: "\f516\f516"; } + +.fa-balance-scale-right { + --fa: "\f516"; + --fa--fa: "\f516\f516"; } + +.fa-subscript { + --fa: "\f12c"; + --fa--fa: "\f12c\f12c"; } + +.fa-diamond-turn-right { + --fa: "\f5eb"; + --fa--fa: "\f5eb\f5eb"; } + +.fa-directions { + --fa: "\f5eb"; + --fa--fa: "\f5eb\f5eb"; } + +.fa-burst { + --fa: "\e4dc"; + --fa--fa: "\e4dc\e4dc"; } + +.fa-house-laptop { + --fa: "\e066"; + --fa--fa: "\e066\e066"; } + +.fa-laptop-house { + --fa: "\e066"; + --fa--fa: "\e066\e066"; } + +.fa-face-tired { + --fa: "\f5c8"; + --fa--fa: "\f5c8\f5c8"; } + +.fa-tired { + --fa: "\f5c8"; + --fa--fa: "\f5c8\f5c8"; } + +.fa-money-bills { + --fa: "\e1f3"; + --fa--fa: "\e1f3\e1f3"; } + +.fa-smog { + --fa: "\f75f"; + --fa--fa: "\f75f\f75f"; } + +.fa-crutch { + --fa: "\f7f7"; + --fa--fa: "\f7f7\f7f7"; } + +.fa-cloud-arrow-up { + --fa: "\f0ee"; + --fa--fa: "\f0ee\f0ee"; } + +.fa-cloud-upload { + --fa: "\f0ee"; + --fa--fa: "\f0ee\f0ee"; } + +.fa-cloud-upload-alt { + --fa: "\f0ee"; + --fa--fa: "\f0ee\f0ee"; } + +.fa-palette { + --fa: "\f53f"; + --fa--fa: "\f53f\f53f"; } + +.fa-arrows-turn-right { + --fa: "\e4c0"; + --fa--fa: "\e4c0\e4c0"; } + +.fa-vest { + --fa: "\e085"; + --fa--fa: "\e085\e085"; } + +.fa-ferry { + --fa: "\e4ea"; + --fa--fa: "\e4ea\e4ea"; } + +.fa-arrows-down-to-people { + --fa: "\e4b9"; + --fa--fa: "\e4b9\e4b9"; } + +.fa-seedling { + --fa: "\f4d8"; + --fa--fa: "\f4d8\f4d8"; } + +.fa-sprout { + --fa: "\f4d8"; + --fa--fa: "\f4d8\f4d8"; } + +.fa-left-right { + --fa: "\f337"; + --fa--fa: "\f337\f337"; } + +.fa-arrows-alt-h { + --fa: "\f337"; + --fa--fa: "\f337\f337"; } + +.fa-boxes-packing { + --fa: "\e4c7"; + --fa--fa: "\e4c7\e4c7"; } + +.fa-circle-arrow-left { + --fa: "\f0a8"; + --fa--fa: "\f0a8\f0a8"; } + +.fa-arrow-circle-left { + --fa: "\f0a8"; + --fa--fa: "\f0a8\f0a8"; } + +.fa-group-arrows-rotate { + --fa: "\e4f6"; + --fa--fa: "\e4f6\e4f6"; } + +.fa-bowl-food { + --fa: "\e4c6"; + --fa--fa: "\e4c6\e4c6"; } + +.fa-candy-cane { + --fa: "\f786"; + --fa--fa: "\f786\f786"; } + +.fa-arrow-down-wide-short { + --fa: "\f160"; + --fa--fa: "\f160\f160"; } + +.fa-sort-amount-asc { + --fa: "\f160"; + --fa--fa: "\f160\f160"; } + +.fa-sort-amount-down { + --fa: "\f160"; + --fa--fa: "\f160\f160"; } + +.fa-cloud-bolt { + --fa: "\f76c"; + --fa--fa: "\f76c\f76c"; } + +.fa-thunderstorm { + --fa: "\f76c"; + --fa--fa: "\f76c\f76c"; } + +.fa-text-slash { + --fa: "\f87d"; + --fa--fa: "\f87d\f87d"; } + +.fa-remove-format { + --fa: "\f87d"; + --fa--fa: "\f87d\f87d"; } + +.fa-face-smile-wink { + --fa: "\f4da"; + --fa--fa: "\f4da\f4da"; } + +.fa-smile-wink { + --fa: "\f4da"; + --fa--fa: "\f4da\f4da"; } + +.fa-file-word { + --fa: "\f1c2"; + --fa--fa: "\f1c2\f1c2"; } + +.fa-file-powerpoint { + --fa: "\f1c4"; + --fa--fa: "\f1c4\f1c4"; } + +.fa-arrows-left-right { + --fa: "\f07e"; + --fa--fa: "\f07e\f07e"; } + +.fa-arrows-h { + --fa: "\f07e"; + --fa--fa: "\f07e\f07e"; } + +.fa-house-lock { + --fa: "\e510"; + --fa--fa: "\e510\e510"; } + +.fa-cloud-arrow-down { + --fa: "\f0ed"; + --fa--fa: "\f0ed\f0ed"; } + +.fa-cloud-download { + --fa: "\f0ed"; + --fa--fa: "\f0ed\f0ed"; } + +.fa-cloud-download-alt { + --fa: "\f0ed"; + --fa--fa: "\f0ed\f0ed"; } + +.fa-children { + --fa: "\e4e1"; + --fa--fa: "\e4e1\e4e1"; } + +.fa-chalkboard { + --fa: "\f51b"; + --fa--fa: "\f51b\f51b"; } + +.fa-blackboard { + --fa: "\f51b"; + --fa--fa: "\f51b\f51b"; } + +.fa-user-large-slash { + --fa: "\f4fa"; + --fa--fa: "\f4fa\f4fa"; } + +.fa-user-alt-slash { + --fa: "\f4fa"; + --fa--fa: "\f4fa\f4fa"; } + +.fa-envelope-open { + --fa: "\f2b6"; + --fa--fa: "\f2b6\f2b6"; } + +.fa-handshake-simple-slash { + --fa: "\e05f"; + --fa--fa: "\e05f\e05f"; } + +.fa-handshake-alt-slash { + --fa: "\e05f"; + --fa--fa: "\e05f\e05f"; } + +.fa-mattress-pillow { + --fa: "\e525"; + --fa--fa: "\e525\e525"; } + +.fa-guarani-sign { + --fa: "\e19a"; + --fa--fa: "\e19a\e19a"; } + +.fa-arrows-rotate { + --fa: "\f021"; + --fa--fa: "\f021\f021"; } + +.fa-refresh { + --fa: "\f021"; + --fa--fa: "\f021\f021"; } + +.fa-sync { + --fa: "\f021"; + --fa--fa: "\f021\f021"; } + +.fa-fire-extinguisher { + --fa: "\f134"; + --fa--fa: "\f134\f134"; } + +.fa-cruzeiro-sign { + --fa: "\e152"; + --fa--fa: "\e152\e152"; } + +.fa-greater-than-equal { + --fa: "\f532"; + --fa--fa: "\f532\f532"; } + +.fa-shield-halved { + --fa: "\f3ed"; + --fa--fa: "\f3ed\f3ed"; } + +.fa-shield-alt { + --fa: "\f3ed"; + --fa--fa: "\f3ed\f3ed"; } + +.fa-book-atlas { + --fa: "\f558"; + --fa--fa: "\f558\f558"; } + +.fa-atlas { + --fa: "\f558"; + --fa--fa: "\f558\f558"; } + +.fa-virus { + --fa: "\e074"; + --fa--fa: "\e074\e074"; } + +.fa-envelope-circle-check { + --fa: "\e4e8"; + --fa--fa: "\e4e8\e4e8"; } + +.fa-layer-group { + --fa: "\f5fd"; + --fa--fa: "\f5fd\f5fd"; } + +.fa-arrows-to-dot { + --fa: "\e4be"; + --fa--fa: "\e4be\e4be"; } + +.fa-archway { + --fa: "\f557"; + --fa--fa: "\f557\f557"; } + +.fa-heart-circle-check { + --fa: "\e4fd"; + --fa--fa: "\e4fd\e4fd"; } + +.fa-house-chimney-crack { + --fa: "\f6f1"; + --fa--fa: "\f6f1\f6f1"; } + +.fa-house-damage { + --fa: "\f6f1"; + --fa--fa: "\f6f1\f6f1"; } + +.fa-file-zipper { + --fa: "\f1c6"; + --fa--fa: "\f1c6\f1c6"; } + +.fa-file-archive { + --fa: "\f1c6"; + --fa--fa: "\f1c6\f1c6"; } + +.fa-square { + --fa: "\f0c8"; + --fa--fa: "\f0c8\f0c8"; } + +.fa-martini-glass-empty { + --fa: "\f000"; + --fa--fa: "\f000\f000"; } + +.fa-glass-martini { + --fa: "\f000"; + --fa--fa: "\f000\f000"; } + +.fa-couch { + --fa: "\f4b8"; + --fa--fa: "\f4b8\f4b8"; } + +.fa-cedi-sign { + --fa: "\e0df"; + --fa--fa: "\e0df\e0df"; } + +.fa-italic { + --fa: "\f033"; + --fa--fa: "\f033\f033"; } + +.fa-table-cells-column-lock { + --fa: "\e678"; + --fa--fa: "\e678\e678"; } + +.fa-church { + --fa: "\f51d"; + --fa--fa: "\f51d\f51d"; } + +.fa-comments-dollar { + --fa: "\f653"; + --fa--fa: "\f653\f653"; } + +.fa-democrat { + --fa: "\f747"; + --fa--fa: "\f747\f747"; } + +.fa-z { + --fa: "\5a"; + --fa--fa: "\5a\5a"; } + +.fa-person-skiing { + --fa: "\f7c9"; + --fa--fa: "\f7c9\f7c9"; } + +.fa-skiing { + --fa: "\f7c9"; + --fa--fa: "\f7c9\f7c9"; } + +.fa-road-lock { + --fa: "\e567"; + --fa--fa: "\e567\e567"; } + +.fa-a { + --fa: "\41"; + --fa--fa: "\41\41"; } + +.fa-temperature-arrow-down { + --fa: "\e03f"; + --fa--fa: "\e03f\e03f"; } + +.fa-temperature-down { + --fa: "\e03f"; + --fa--fa: "\e03f\e03f"; } + +.fa-feather-pointed { + --fa: "\f56b"; + --fa--fa: "\f56b\f56b"; } + +.fa-feather-alt { + --fa: "\f56b"; + --fa--fa: "\f56b\f56b"; } + +.fa-p { + --fa: "\50"; + --fa--fa: "\50\50"; } + +.fa-snowflake { + --fa: "\f2dc"; + --fa--fa: "\f2dc\f2dc"; } + +.fa-newspaper { + --fa: "\f1ea"; + --fa--fa: "\f1ea\f1ea"; } + +.fa-rectangle-ad { + --fa: "\f641"; + --fa--fa: "\f641\f641"; } + +.fa-ad { + --fa: "\f641"; + --fa--fa: "\f641\f641"; } + +.fa-circle-arrow-right { + --fa: "\f0a9"; + --fa--fa: "\f0a9\f0a9"; } + +.fa-arrow-circle-right { + --fa: "\f0a9"; + --fa--fa: "\f0a9\f0a9"; } + +.fa-filter-circle-xmark { + --fa: "\e17b"; + --fa--fa: "\e17b\e17b"; } + +.fa-locust { + --fa: "\e520"; + --fa--fa: "\e520\e520"; } + +.fa-sort { + --fa: "\f0dc"; + --fa--fa: "\f0dc\f0dc"; } + +.fa-unsorted { + --fa: "\f0dc"; + --fa--fa: "\f0dc\f0dc"; } + +.fa-list-ol { + --fa: "\f0cb"; + --fa--fa: "\f0cb\f0cb"; } + +.fa-list-1-2 { + --fa: "\f0cb"; + --fa--fa: "\f0cb\f0cb"; } + +.fa-list-numeric { + --fa: "\f0cb"; + --fa--fa: "\f0cb\f0cb"; } + +.fa-person-dress-burst { + --fa: "\e544"; + --fa--fa: "\e544\e544"; } + +.fa-money-check-dollar { + --fa: "\f53d"; + --fa--fa: "\f53d\f53d"; } + +.fa-money-check-alt { + --fa: "\f53d"; + --fa--fa: "\f53d\f53d"; } + +.fa-vector-square { + --fa: "\f5cb"; + --fa--fa: "\f5cb\f5cb"; } + +.fa-bread-slice { + --fa: "\f7ec"; + --fa--fa: "\f7ec\f7ec"; } + +.fa-language { + --fa: "\f1ab"; + --fa--fa: "\f1ab\f1ab"; } + +.fa-face-kiss-wink-heart { + --fa: "\f598"; + --fa--fa: "\f598\f598"; } + +.fa-kiss-wink-heart { + --fa: "\f598"; + --fa--fa: "\f598\f598"; } + +.fa-filter { + --fa: "\f0b0"; + --fa--fa: "\f0b0\f0b0"; } + +.fa-question { + --fa: "\3f"; + --fa--fa: "\3f\3f"; } + +.fa-file-signature { + --fa: "\f573"; + --fa--fa: "\f573\f573"; } + +.fa-up-down-left-right { + --fa: "\f0b2"; + --fa--fa: "\f0b2\f0b2"; } + +.fa-arrows-alt { + --fa: "\f0b2"; + --fa--fa: "\f0b2\f0b2"; } + +.fa-house-chimney-user { + --fa: "\e065"; + --fa--fa: "\e065\e065"; } + +.fa-hand-holding-heart { + --fa: "\f4be"; + --fa--fa: "\f4be\f4be"; } + +.fa-puzzle-piece { + --fa: "\f12e"; + --fa--fa: "\f12e\f12e"; } + +.fa-money-check { + --fa: "\f53c"; + --fa--fa: "\f53c\f53c"; } + +.fa-star-half-stroke { + --fa: "\f5c0"; + --fa--fa: "\f5c0\f5c0"; } + +.fa-star-half-alt { + --fa: "\f5c0"; + --fa--fa: "\f5c0\f5c0"; } + +.fa-code { + --fa: "\f121"; + --fa--fa: "\f121\f121"; } + +.fa-whiskey-glass { + --fa: "\f7a0"; + --fa--fa: "\f7a0\f7a0"; } + +.fa-glass-whiskey { + --fa: "\f7a0"; + --fa--fa: "\f7a0\f7a0"; } + +.fa-building-circle-exclamation { + --fa: "\e4d3"; + --fa--fa: "\e4d3\e4d3"; } + +.fa-magnifying-glass-chart { + --fa: "\e522"; + --fa--fa: "\e522\e522"; } + +.fa-arrow-up-right-from-square { + --fa: "\f08e"; + --fa--fa: "\f08e\f08e"; } + +.fa-external-link { + --fa: "\f08e"; + --fa--fa: "\f08e\f08e"; } + +.fa-cubes-stacked { + --fa: "\e4e6"; + --fa--fa: "\e4e6\e4e6"; } + +.fa-won-sign { + --fa: "\f159"; + --fa--fa: "\f159\f159"; } + +.fa-krw { + --fa: "\f159"; + --fa--fa: "\f159\f159"; } + +.fa-won { + --fa: "\f159"; + --fa--fa: "\f159\f159"; } + +.fa-virus-covid { + --fa: "\e4a8"; + --fa--fa: "\e4a8\e4a8"; } + +.fa-austral-sign { + --fa: "\e0a9"; + --fa--fa: "\e0a9\e0a9"; } + +.fa-f { + --fa: "\46"; + --fa--fa: "\46\46"; } + +.fa-leaf { + --fa: "\f06c"; + --fa--fa: "\f06c\f06c"; } + +.fa-road { + --fa: "\f018"; + --fa--fa: "\f018\f018"; } + +.fa-taxi { + --fa: "\f1ba"; + --fa--fa: "\f1ba\f1ba"; } + +.fa-cab { + --fa: "\f1ba"; + --fa--fa: "\f1ba\f1ba"; } + +.fa-person-circle-plus { + --fa: "\e541"; + --fa--fa: "\e541\e541"; } + +.fa-chart-pie { + --fa: "\f200"; + --fa--fa: "\f200\f200"; } + +.fa-pie-chart { + --fa: "\f200"; + --fa--fa: "\f200\f200"; } + +.fa-bolt-lightning { + --fa: "\e0b7"; + --fa--fa: "\e0b7\e0b7"; } + +.fa-sack-xmark { + --fa: "\e56a"; + --fa--fa: "\e56a\e56a"; } + +.fa-file-excel { + --fa: "\f1c3"; + --fa--fa: "\f1c3\f1c3"; } + +.fa-file-contract { + --fa: "\f56c"; + --fa--fa: "\f56c\f56c"; } + +.fa-fish-fins { + --fa: "\e4f2"; + --fa--fa: "\e4f2\e4f2"; } + +.fa-building-flag { + --fa: "\e4d5"; + --fa--fa: "\e4d5\e4d5"; } + +.fa-face-grin-beam { + --fa: "\f582"; + --fa--fa: "\f582\f582"; } + +.fa-grin-beam { + --fa: "\f582"; + --fa--fa: "\f582\f582"; } + +.fa-object-ungroup { + --fa: "\f248"; + --fa--fa: "\f248\f248"; } + +.fa-poop { + --fa: "\f619"; + --fa--fa: "\f619\f619"; } + +.fa-location-pin { + --fa: "\f041"; + --fa--fa: "\f041\f041"; } + +.fa-map-marker { + --fa: "\f041"; + --fa--fa: "\f041\f041"; } + +.fa-kaaba { + --fa: "\f66b"; + --fa--fa: "\f66b\f66b"; } + +.fa-toilet-paper { + --fa: "\f71e"; + --fa--fa: "\f71e\f71e"; } + +.fa-helmet-safety { + --fa: "\f807"; + --fa--fa: "\f807\f807"; } + +.fa-hard-hat { + --fa: "\f807"; + --fa--fa: "\f807\f807"; } + +.fa-hat-hard { + --fa: "\f807"; + --fa--fa: "\f807\f807"; } + +.fa-eject { + --fa: "\f052"; + --fa--fa: "\f052\f052"; } + +.fa-circle-right { + --fa: "\f35a"; + --fa--fa: "\f35a\f35a"; } + +.fa-arrow-alt-circle-right { + --fa: "\f35a"; + --fa--fa: "\f35a\f35a"; } + +.fa-plane-circle-check { + --fa: "\e555"; + --fa--fa: "\e555\e555"; } + +.fa-face-rolling-eyes { + --fa: "\f5a5"; + --fa--fa: "\f5a5\f5a5"; } + +.fa-meh-rolling-eyes { + --fa: "\f5a5"; + --fa--fa: "\f5a5\f5a5"; } + +.fa-object-group { + --fa: "\f247"; + --fa--fa: "\f247\f247"; } + +.fa-chart-line { + --fa: "\f201"; + --fa--fa: "\f201\f201"; } + +.fa-line-chart { + --fa: "\f201"; + --fa--fa: "\f201\f201"; } + +.fa-mask-ventilator { + --fa: "\e524"; + --fa--fa: "\e524\e524"; } + +.fa-arrow-right { + --fa: "\f061"; + --fa--fa: "\f061\f061"; } + +.fa-signs-post { + --fa: "\f277"; + --fa--fa: "\f277\f277"; } + +.fa-map-signs { + --fa: "\f277"; + --fa--fa: "\f277\f277"; } + +.fa-cash-register { + --fa: "\f788"; + --fa--fa: "\f788\f788"; } + +.fa-person-circle-question { + --fa: "\e542"; + --fa--fa: "\e542\e542"; } + +.fa-h { + --fa: "\48"; + --fa--fa: "\48\48"; } + +.fa-tarp { + --fa: "\e57b"; + --fa--fa: "\e57b\e57b"; } + +.fa-screwdriver-wrench { + --fa: "\f7d9"; + --fa--fa: "\f7d9\f7d9"; } + +.fa-tools { + --fa: "\f7d9"; + --fa--fa: "\f7d9\f7d9"; } + +.fa-arrows-to-eye { + --fa: "\e4bf"; + --fa--fa: "\e4bf\e4bf"; } + +.fa-plug-circle-bolt { + --fa: "\e55b"; + --fa--fa: "\e55b\e55b"; } + +.fa-heart { + --fa: "\f004"; + --fa--fa: "\f004\f004"; } + +.fa-mars-and-venus { + --fa: "\f224"; + --fa--fa: "\f224\f224"; } + +.fa-house-user { + --fa: "\e1b0"; + --fa--fa: "\e1b0\e1b0"; } + +.fa-home-user { + --fa: "\e1b0"; + --fa--fa: "\e1b0\e1b0"; } + +.fa-dumpster-fire { + --fa: "\f794"; + --fa--fa: "\f794\f794"; } + +.fa-house-crack { + --fa: "\e3b1"; + --fa--fa: "\e3b1\e3b1"; } + +.fa-martini-glass-citrus { + --fa: "\f561"; + --fa--fa: "\f561\f561"; } + +.fa-cocktail { + --fa: "\f561"; + --fa--fa: "\f561\f561"; } + +.fa-face-surprise { + --fa: "\f5c2"; + --fa--fa: "\f5c2\f5c2"; } + +.fa-surprise { + --fa: "\f5c2"; + --fa--fa: "\f5c2\f5c2"; } + +.fa-bottle-water { + --fa: "\e4c5"; + --fa--fa: "\e4c5\e4c5"; } + +.fa-circle-pause { + --fa: "\f28b"; + --fa--fa: "\f28b\f28b"; } + +.fa-pause-circle { + --fa: "\f28b"; + --fa--fa: "\f28b\f28b"; } + +.fa-toilet-paper-slash { + --fa: "\e072"; + --fa--fa: "\e072\e072"; } + +.fa-apple-whole { + --fa: "\f5d1"; + --fa--fa: "\f5d1\f5d1"; } + +.fa-apple-alt { + --fa: "\f5d1"; + --fa--fa: "\f5d1\f5d1"; } + +.fa-kitchen-set { + --fa: "\e51a"; + --fa--fa: "\e51a\e51a"; } + +.fa-r { + --fa: "\52"; + --fa--fa: "\52\52"; } + +.fa-temperature-quarter { + --fa: "\f2ca"; + --fa--fa: "\f2ca\f2ca"; } + +.fa-temperature-1 { + --fa: "\f2ca"; + --fa--fa: "\f2ca\f2ca"; } + +.fa-thermometer-1 { + --fa: "\f2ca"; + --fa--fa: "\f2ca\f2ca"; } + +.fa-thermometer-quarter { + --fa: "\f2ca"; + --fa--fa: "\f2ca\f2ca"; } + +.fa-cube { + --fa: "\f1b2"; + --fa--fa: "\f1b2\f1b2"; } + +.fa-bitcoin-sign { + --fa: "\e0b4"; + --fa--fa: "\e0b4\e0b4"; } + +.fa-shield-dog { + --fa: "\e573"; + --fa--fa: "\e573\e573"; } + +.fa-solar-panel { + --fa: "\f5ba"; + --fa--fa: "\f5ba\f5ba"; } + +.fa-lock-open { + --fa: "\f3c1"; + --fa--fa: "\f3c1\f3c1"; } + +.fa-elevator { + --fa: "\e16d"; + --fa--fa: "\e16d\e16d"; } + +.fa-money-bill-transfer { + --fa: "\e528"; + --fa--fa: "\e528\e528"; } + +.fa-money-bill-trend-up { + --fa: "\e529"; + --fa--fa: "\e529\e529"; } + +.fa-house-flood-water-circle-arrow-right { + --fa: "\e50f"; + --fa--fa: "\e50f\e50f"; } + +.fa-square-poll-horizontal { + --fa: "\f682"; + --fa--fa: "\f682\f682"; } + +.fa-poll-h { + --fa: "\f682"; + --fa--fa: "\f682\f682"; } + +.fa-circle { + --fa: "\f111"; + --fa--fa: "\f111\f111"; } + +.fa-backward-fast { + --fa: "\f049"; + --fa--fa: "\f049\f049"; } + +.fa-fast-backward { + --fa: "\f049"; + --fa--fa: "\f049\f049"; } + +.fa-recycle { + --fa: "\f1b8"; + --fa--fa: "\f1b8\f1b8"; } + +.fa-user-astronaut { + --fa: "\f4fb"; + --fa--fa: "\f4fb\f4fb"; } + +.fa-plane-slash { + --fa: "\e069"; + --fa--fa: "\e069\e069"; } + +.fa-trademark { + --fa: "\f25c"; + --fa--fa: "\f25c\f25c"; } + +.fa-basketball { + --fa: "\f434"; + --fa--fa: "\f434\f434"; } + +.fa-basketball-ball { + --fa: "\f434"; + --fa--fa: "\f434\f434"; } + +.fa-satellite-dish { + --fa: "\f7c0"; + --fa--fa: "\f7c0\f7c0"; } + +.fa-circle-up { + --fa: "\f35b"; + --fa--fa: "\f35b\f35b"; } + +.fa-arrow-alt-circle-up { + --fa: "\f35b"; + --fa--fa: "\f35b\f35b"; } + +.fa-mobile-screen-button { + --fa: "\f3cd"; + --fa--fa: "\f3cd\f3cd"; } + +.fa-mobile-alt { + --fa: "\f3cd"; + --fa--fa: "\f3cd\f3cd"; } + +.fa-volume-high { + --fa: "\f028"; + --fa--fa: "\f028\f028"; } + +.fa-volume-up { + --fa: "\f028"; + --fa--fa: "\f028\f028"; } + +.fa-users-rays { + --fa: "\e593"; + --fa--fa: "\e593\e593"; } + +.fa-wallet { + --fa: "\f555"; + --fa--fa: "\f555\f555"; } + +.fa-clipboard-check { + --fa: "\f46c"; + --fa--fa: "\f46c\f46c"; } + +.fa-file-audio { + --fa: "\f1c7"; + --fa--fa: "\f1c7\f1c7"; } + +.fa-burger { + --fa: "\f805"; + --fa--fa: "\f805\f805"; } + +.fa-hamburger { + --fa: "\f805"; + --fa--fa: "\f805\f805"; } + +.fa-wrench { + --fa: "\f0ad"; + --fa--fa: "\f0ad\f0ad"; } + +.fa-bugs { + --fa: "\e4d0"; + --fa--fa: "\e4d0\e4d0"; } + +.fa-rupee-sign { + --fa: "\f156"; + --fa--fa: "\f156\f156"; } + +.fa-rupee { + --fa: "\f156"; + --fa--fa: "\f156\f156"; } + +.fa-file-image { + --fa: "\f1c5"; + --fa--fa: "\f1c5\f1c5"; } + +.fa-circle-question { + --fa: "\f059"; + --fa--fa: "\f059\f059"; } + +.fa-question-circle { + --fa: "\f059"; + --fa--fa: "\f059\f059"; } + +.fa-plane-departure { + --fa: "\f5b0"; + --fa--fa: "\f5b0\f5b0"; } + +.fa-handshake-slash { + --fa: "\e060"; + --fa--fa: "\e060\e060"; } + +.fa-book-bookmark { + --fa: "\e0bb"; + --fa--fa: "\e0bb\e0bb"; } + +.fa-code-branch { + --fa: "\f126"; + --fa--fa: "\f126\f126"; } + +.fa-hat-cowboy { + --fa: "\f8c0"; + --fa--fa: "\f8c0\f8c0"; } + +.fa-bridge { + --fa: "\e4c8"; + --fa--fa: "\e4c8\e4c8"; } + +.fa-phone-flip { + --fa: "\f879"; + --fa--fa: "\f879\f879"; } + +.fa-phone-alt { + --fa: "\f879"; + --fa--fa: "\f879\f879"; } + +.fa-truck-front { + --fa: "\e2b7"; + --fa--fa: "\e2b7\e2b7"; } + +.fa-cat { + --fa: "\f6be"; + --fa--fa: "\f6be\f6be"; } + +.fa-anchor-circle-exclamation { + --fa: "\e4ab"; + --fa--fa: "\e4ab\e4ab"; } + +.fa-truck-field { + --fa: "\e58d"; + --fa--fa: "\e58d\e58d"; } + +.fa-route { + --fa: "\f4d7"; + --fa--fa: "\f4d7\f4d7"; } + +.fa-clipboard-question { + --fa: "\e4e3"; + --fa--fa: "\e4e3\e4e3"; } + +.fa-panorama { + --fa: "\e209"; + --fa--fa: "\e209\e209"; } + +.fa-comment-medical { + --fa: "\f7f5"; + --fa--fa: "\f7f5\f7f5"; } + +.fa-teeth-open { + --fa: "\f62f"; + --fa--fa: "\f62f\f62f"; } + +.fa-file-circle-minus { + --fa: "\e4ed"; + --fa--fa: "\e4ed\e4ed"; } + +.fa-tags { + --fa: "\f02c"; + --fa--fa: "\f02c\f02c"; } + +.fa-wine-glass { + --fa: "\f4e3"; + --fa--fa: "\f4e3\f4e3"; } + +.fa-forward-fast { + --fa: "\f050"; + --fa--fa: "\f050\f050"; } + +.fa-fast-forward { + --fa: "\f050"; + --fa--fa: "\f050\f050"; } + +.fa-face-meh-blank { + --fa: "\f5a4"; + --fa--fa: "\f5a4\f5a4"; } + +.fa-meh-blank { + --fa: "\f5a4"; + --fa--fa: "\f5a4\f5a4"; } + +.fa-square-parking { + --fa: "\f540"; + --fa--fa: "\f540\f540"; } + +.fa-parking { + --fa: "\f540"; + --fa--fa: "\f540\f540"; } + +.fa-house-signal { + --fa: "\e012"; + --fa--fa: "\e012\e012"; } + +.fa-bars-progress { + --fa: "\f828"; + --fa--fa: "\f828\f828"; } + +.fa-tasks-alt { + --fa: "\f828"; + --fa--fa: "\f828\f828"; } + +.fa-faucet-drip { + --fa: "\e006"; + --fa--fa: "\e006\e006"; } + +.fa-cart-flatbed { + --fa: "\f474"; + --fa--fa: "\f474\f474"; } + +.fa-dolly-flatbed { + --fa: "\f474"; + --fa--fa: "\f474\f474"; } + +.fa-ban-smoking { + --fa: "\f54d"; + --fa--fa: "\f54d\f54d"; } + +.fa-smoking-ban { + --fa: "\f54d"; + --fa--fa: "\f54d\f54d"; } + +.fa-terminal { + --fa: "\f120"; + --fa--fa: "\f120\f120"; } + +.fa-mobile-button { + --fa: "\f10b"; + --fa--fa: "\f10b\f10b"; } + +.fa-house-medical-flag { + --fa: "\e514"; + --fa--fa: "\e514\e514"; } + +.fa-basket-shopping { + --fa: "\f291"; + --fa--fa: "\f291\f291"; } + +.fa-shopping-basket { + --fa: "\f291"; + --fa--fa: "\f291\f291"; } + +.fa-tape { + --fa: "\f4db"; + --fa--fa: "\f4db\f4db"; } + +.fa-bus-simple { + --fa: "\f55e"; + --fa--fa: "\f55e\f55e"; } + +.fa-bus-alt { + --fa: "\f55e"; + --fa--fa: "\f55e\f55e"; } + +.fa-eye { + --fa: "\f06e"; + --fa--fa: "\f06e\f06e"; } + +.fa-face-sad-cry { + --fa: "\f5b3"; + --fa--fa: "\f5b3\f5b3"; } + +.fa-sad-cry { + --fa: "\f5b3"; + --fa--fa: "\f5b3\f5b3"; } + +.fa-audio-description { + --fa: "\f29e"; + --fa--fa: "\f29e\f29e"; } + +.fa-person-military-to-person { + --fa: "\e54c"; + --fa--fa: "\e54c\e54c"; } + +.fa-file-shield { + --fa: "\e4f0"; + --fa--fa: "\e4f0\e4f0"; } + +.fa-user-slash { + --fa: "\f506"; + --fa--fa: "\f506\f506"; } + +.fa-pen { + --fa: "\f304"; + --fa--fa: "\f304\f304"; } + +.fa-tower-observation { + --fa: "\e586"; + --fa--fa: "\e586\e586"; } + +.fa-file-code { + --fa: "\f1c9"; + --fa--fa: "\f1c9\f1c9"; } + +.fa-signal { + --fa: "\f012"; + --fa--fa: "\f012\f012"; } + +.fa-signal-5 { + --fa: "\f012"; + --fa--fa: "\f012\f012"; } + +.fa-signal-perfect { + --fa: "\f012"; + --fa--fa: "\f012\f012"; } + +.fa-bus { + --fa: "\f207"; + --fa--fa: "\f207\f207"; } + +.fa-heart-circle-xmark { + --fa: "\e501"; + --fa--fa: "\e501\e501"; } + +.fa-house-chimney { + --fa: "\e3af"; + --fa--fa: "\e3af\e3af"; } + +.fa-home-lg { + --fa: "\e3af"; + --fa--fa: "\e3af\e3af"; } + +.fa-window-maximize { + --fa: "\f2d0"; + --fa--fa: "\f2d0\f2d0"; } + +.fa-face-frown { + --fa: "\f119"; + --fa--fa: "\f119\f119"; } + +.fa-frown { + --fa: "\f119"; + --fa--fa: "\f119\f119"; } + +.fa-prescription { + --fa: "\f5b1"; + --fa--fa: "\f5b1\f5b1"; } + +.fa-shop { + --fa: "\f54f"; + --fa--fa: "\f54f\f54f"; } + +.fa-store-alt { + --fa: "\f54f"; + --fa--fa: "\f54f\f54f"; } + +.fa-floppy-disk { + --fa: "\f0c7"; + --fa--fa: "\f0c7\f0c7"; } + +.fa-save { + --fa: "\f0c7"; + --fa--fa: "\f0c7\f0c7"; } + +.fa-vihara { + --fa: "\f6a7"; + --fa--fa: "\f6a7\f6a7"; } + +.fa-scale-unbalanced { + --fa: "\f515"; + --fa--fa: "\f515\f515"; } + +.fa-balance-scale-left { + --fa: "\f515"; + --fa--fa: "\f515\f515"; } + +.fa-sort-up { + --fa: "\f0de"; + --fa--fa: "\f0de\f0de"; } + +.fa-sort-asc { + --fa: "\f0de"; + --fa--fa: "\f0de\f0de"; } + +.fa-comment-dots { + --fa: "\f4ad"; + --fa--fa: "\f4ad\f4ad"; } + +.fa-commenting { + --fa: "\f4ad"; + --fa--fa: "\f4ad\f4ad"; } + +.fa-plant-wilt { + --fa: "\e5aa"; + --fa--fa: "\e5aa\e5aa"; } + +.fa-diamond { + --fa: "\f219"; + --fa--fa: "\f219\f219"; } + +.fa-face-grin-squint { + --fa: "\f585"; + --fa--fa: "\f585\f585"; } + +.fa-grin-squint { + --fa: "\f585"; + --fa--fa: "\f585\f585"; } + +.fa-hand-holding-dollar { + --fa: "\f4c0"; + --fa--fa: "\f4c0\f4c0"; } + +.fa-hand-holding-usd { + --fa: "\f4c0"; + --fa--fa: "\f4c0\f4c0"; } + +.fa-chart-diagram { + --fa: "\e695"; + --fa--fa: "\e695\e695"; } + +.fa-bacterium { + --fa: "\e05a"; + --fa--fa: "\e05a\e05a"; } + +.fa-hand-pointer { + --fa: "\f25a"; + --fa--fa: "\f25a\f25a"; } + +.fa-drum-steelpan { + --fa: "\f56a"; + --fa--fa: "\f56a\f56a"; } + +.fa-hand-scissors { + --fa: "\f257"; + --fa--fa: "\f257\f257"; } + +.fa-hands-praying { + --fa: "\f684"; + --fa--fa: "\f684\f684"; } + +.fa-praying-hands { + --fa: "\f684"; + --fa--fa: "\f684\f684"; } + +.fa-arrow-rotate-right { + --fa: "\f01e"; + --fa--fa: "\f01e\f01e"; } + +.fa-arrow-right-rotate { + --fa: "\f01e"; + --fa--fa: "\f01e\f01e"; } + +.fa-arrow-rotate-forward { + --fa: "\f01e"; + --fa--fa: "\f01e\f01e"; } + +.fa-redo { + --fa: "\f01e"; + --fa--fa: "\f01e\f01e"; } + +.fa-biohazard { + --fa: "\f780"; + --fa--fa: "\f780\f780"; } + +.fa-location-crosshairs { + --fa: "\f601"; + --fa--fa: "\f601\f601"; } + +.fa-location { + --fa: "\f601"; + --fa--fa: "\f601\f601"; } + +.fa-mars-double { + --fa: "\f227"; + --fa--fa: "\f227\f227"; } + +.fa-child-dress { + --fa: "\e59c"; + --fa--fa: "\e59c\e59c"; } + +.fa-users-between-lines { + --fa: "\e591"; + --fa--fa: "\e591\e591"; } + +.fa-lungs-virus { + --fa: "\e067"; + --fa--fa: "\e067\e067"; } + +.fa-face-grin-tears { + --fa: "\f588"; + --fa--fa: "\f588\f588"; } + +.fa-grin-tears { + --fa: "\f588"; + --fa--fa: "\f588\f588"; } + +.fa-phone { + --fa: "\f095"; + --fa--fa: "\f095\f095"; } + +.fa-calendar-xmark { + --fa: "\f273"; + --fa--fa: "\f273\f273"; } + +.fa-calendar-times { + --fa: "\f273"; + --fa--fa: "\f273\f273"; } + +.fa-child-reaching { + --fa: "\e59d"; + --fa--fa: "\e59d\e59d"; } + +.fa-head-side-virus { + --fa: "\e064"; + --fa--fa: "\e064\e064"; } + +.fa-user-gear { + --fa: "\f4fe"; + --fa--fa: "\f4fe\f4fe"; } + +.fa-user-cog { + --fa: "\f4fe"; + --fa--fa: "\f4fe\f4fe"; } + +.fa-arrow-up-1-9 { + --fa: "\f163"; + --fa--fa: "\f163\f163"; } + +.fa-sort-numeric-up { + --fa: "\f163"; + --fa--fa: "\f163\f163"; } + +.fa-door-closed { + --fa: "\f52a"; + --fa--fa: "\f52a\f52a"; } + +.fa-shield-virus { + --fa: "\e06c"; + --fa--fa: "\e06c\e06c"; } + +.fa-dice-six { + --fa: "\f526"; + --fa--fa: "\f526\f526"; } + +.fa-mosquito-net { + --fa: "\e52c"; + --fa--fa: "\e52c\e52c"; } + +.fa-file-fragment { + --fa: "\e697"; + --fa--fa: "\e697\e697"; } + +.fa-bridge-water { + --fa: "\e4ce"; + --fa--fa: "\e4ce\e4ce"; } + +.fa-person-booth { + --fa: "\f756"; + --fa--fa: "\f756\f756"; } + +.fa-text-width { + --fa: "\f035"; + --fa--fa: "\f035\f035"; } + +.fa-hat-wizard { + --fa: "\f6e8"; + --fa--fa: "\f6e8\f6e8"; } + +.fa-pen-fancy { + --fa: "\f5ac"; + --fa--fa: "\f5ac\f5ac"; } + +.fa-person-digging { + --fa: "\f85e"; + --fa--fa: "\f85e\f85e"; } + +.fa-digging { + --fa: "\f85e"; + --fa--fa: "\f85e\f85e"; } + +.fa-trash { + --fa: "\f1f8"; + --fa--fa: "\f1f8\f1f8"; } + +.fa-gauge-simple { + --fa: "\f629"; + --fa--fa: "\f629\f629"; } + +.fa-gauge-simple-med { + --fa: "\f629"; + --fa--fa: "\f629\f629"; } + +.fa-tachometer-average { + --fa: "\f629"; + --fa--fa: "\f629\f629"; } + +.fa-book-medical { + --fa: "\f7e6"; + --fa--fa: "\f7e6\f7e6"; } + +.fa-poo { + --fa: "\f2fe"; + --fa--fa: "\f2fe\f2fe"; } + +.fa-quote-right { + --fa: "\f10e"; + --fa--fa: "\f10e\f10e"; } + +.fa-quote-right-alt { + --fa: "\f10e"; + --fa--fa: "\f10e\f10e"; } + +.fa-shirt { + --fa: "\f553"; + --fa--fa: "\f553\f553"; } + +.fa-t-shirt { + --fa: "\f553"; + --fa--fa: "\f553\f553"; } + +.fa-tshirt { + --fa: "\f553"; + --fa--fa: "\f553\f553"; } + +.fa-cubes { + --fa: "\f1b3"; + --fa--fa: "\f1b3\f1b3"; } + +.fa-divide { + --fa: "\f529"; + --fa--fa: "\f529\f529"; } + +.fa-tenge-sign { + --fa: "\f7d7"; + --fa--fa: "\f7d7\f7d7"; } + +.fa-tenge { + --fa: "\f7d7"; + --fa--fa: "\f7d7\f7d7"; } + +.fa-headphones { + --fa: "\f025"; + --fa--fa: "\f025\f025"; } + +.fa-hands-holding { + --fa: "\f4c2"; + --fa--fa: "\f4c2\f4c2"; } + +.fa-hands-clapping { + --fa: "\e1a8"; + --fa--fa: "\e1a8\e1a8"; } + +.fa-republican { + --fa: "\f75e"; + --fa--fa: "\f75e\f75e"; } + +.fa-arrow-left { + --fa: "\f060"; + --fa--fa: "\f060\f060"; } + +.fa-person-circle-xmark { + --fa: "\e543"; + --fa--fa: "\e543\e543"; } + +.fa-ruler { + --fa: "\f545"; + --fa--fa: "\f545\f545"; } + +.fa-align-left { + --fa: "\f036"; + --fa--fa: "\f036\f036"; } + +.fa-dice-d6 { + --fa: "\f6d1"; + --fa--fa: "\f6d1\f6d1"; } + +.fa-restroom { + --fa: "\f7bd"; + --fa--fa: "\f7bd\f7bd"; } + +.fa-j { + --fa: "\4a"; + --fa--fa: "\4a\4a"; } + +.fa-users-viewfinder { + --fa: "\e595"; + --fa--fa: "\e595\e595"; } + +.fa-file-video { + --fa: "\f1c8"; + --fa--fa: "\f1c8\f1c8"; } + +.fa-up-right-from-square { + --fa: "\f35d"; + --fa--fa: "\f35d\f35d"; } + +.fa-external-link-alt { + --fa: "\f35d"; + --fa--fa: "\f35d\f35d"; } + +.fa-table-cells { + --fa: "\f00a"; + --fa--fa: "\f00a\f00a"; } + +.fa-th { + --fa: "\f00a"; + --fa--fa: "\f00a\f00a"; } + +.fa-file-pdf { + --fa: "\f1c1"; + --fa--fa: "\f1c1\f1c1"; } + +.fa-book-bible { + --fa: "\f647"; + --fa--fa: "\f647\f647"; } + +.fa-bible { + --fa: "\f647"; + --fa--fa: "\f647\f647"; } + +.fa-o { + --fa: "\4f"; + --fa--fa: "\4f\4f"; } + +.fa-suitcase-medical { + --fa: "\f0fa"; + --fa--fa: "\f0fa\f0fa"; } + +.fa-medkit { + --fa: "\f0fa"; + --fa--fa: "\f0fa\f0fa"; } + +.fa-user-secret { + --fa: "\f21b"; + --fa--fa: "\f21b\f21b"; } + +.fa-otter { + --fa: "\f700"; + --fa--fa: "\f700\f700"; } + +.fa-person-dress { + --fa: "\f182"; + --fa--fa: "\f182\f182"; } + +.fa-female { + --fa: "\f182"; + --fa--fa: "\f182\f182"; } + +.fa-comment-dollar { + --fa: "\f651"; + --fa--fa: "\f651\f651"; } + +.fa-business-time { + --fa: "\f64a"; + --fa--fa: "\f64a\f64a"; } + +.fa-briefcase-clock { + --fa: "\f64a"; + --fa--fa: "\f64a\f64a"; } + +.fa-table-cells-large { + --fa: "\f009"; + --fa--fa: "\f009\f009"; } + +.fa-th-large { + --fa: "\f009"; + --fa--fa: "\f009\f009"; } + +.fa-book-tanakh { + --fa: "\f827"; + --fa--fa: "\f827\f827"; } + +.fa-tanakh { + --fa: "\f827"; + --fa--fa: "\f827\f827"; } + +.fa-phone-volume { + --fa: "\f2a0"; + --fa--fa: "\f2a0\f2a0"; } + +.fa-volume-control-phone { + --fa: "\f2a0"; + --fa--fa: "\f2a0\f2a0"; } + +.fa-hat-cowboy-side { + --fa: "\f8c1"; + --fa--fa: "\f8c1\f8c1"; } + +.fa-clipboard-user { + --fa: "\f7f3"; + --fa--fa: "\f7f3\f7f3"; } + +.fa-child { + --fa: "\f1ae"; + --fa--fa: "\f1ae\f1ae"; } + +.fa-lira-sign { + --fa: "\f195"; + --fa--fa: "\f195\f195"; } + +.fa-satellite { + --fa: "\f7bf"; + --fa--fa: "\f7bf\f7bf"; } + +.fa-plane-lock { + --fa: "\e558"; + --fa--fa: "\e558\e558"; } + +.fa-tag { + --fa: "\f02b"; + --fa--fa: "\f02b\f02b"; } + +.fa-comment { + --fa: "\f075"; + --fa--fa: "\f075\f075"; } + +.fa-cake-candles { + --fa: "\f1fd"; + --fa--fa: "\f1fd\f1fd"; } + +.fa-birthday-cake { + --fa: "\f1fd"; + --fa--fa: "\f1fd\f1fd"; } + +.fa-cake { + --fa: "\f1fd"; + --fa--fa: "\f1fd\f1fd"; } + +.fa-envelope { + --fa: "\f0e0"; + --fa--fa: "\f0e0\f0e0"; } + +.fa-angles-up { + --fa: "\f102"; + --fa--fa: "\f102\f102"; } + +.fa-angle-double-up { + --fa: "\f102"; + --fa--fa: "\f102\f102"; } + +.fa-paperclip { + --fa: "\f0c6"; + --fa--fa: "\f0c6\f0c6"; } + +.fa-arrow-right-to-city { + --fa: "\e4b3"; + --fa--fa: "\e4b3\e4b3"; } + +.fa-ribbon { + --fa: "\f4d6"; + --fa--fa: "\f4d6\f4d6"; } + +.fa-lungs { + --fa: "\f604"; + --fa--fa: "\f604\f604"; } + +.fa-arrow-up-9-1 { + --fa: "\f887"; + --fa--fa: "\f887\f887"; } + +.fa-sort-numeric-up-alt { + --fa: "\f887"; + --fa--fa: "\f887\f887"; } + +.fa-litecoin-sign { + --fa: "\e1d3"; + --fa--fa: "\e1d3\e1d3"; } + +.fa-border-none { + --fa: "\f850"; + --fa--fa: "\f850\f850"; } + +.fa-circle-nodes { + --fa: "\e4e2"; + --fa--fa: "\e4e2\e4e2"; } + +.fa-parachute-box { + --fa: "\f4cd"; + --fa--fa: "\f4cd\f4cd"; } + +.fa-indent { + --fa: "\f03c"; + --fa--fa: "\f03c\f03c"; } + +.fa-truck-field-un { + --fa: "\e58e"; + --fa--fa: "\e58e\e58e"; } + +.fa-hourglass { + --fa: "\f254"; + --fa--fa: "\f254\f254"; } + +.fa-hourglass-empty { + --fa: "\f254"; + --fa--fa: "\f254\f254"; } + +.fa-mountain { + --fa: "\f6fc"; + --fa--fa: "\f6fc\f6fc"; } + +.fa-user-doctor { + --fa: "\f0f0"; + --fa--fa: "\f0f0\f0f0"; } + +.fa-user-md { + --fa: "\f0f0"; + --fa--fa: "\f0f0\f0f0"; } + +.fa-circle-info { + --fa: "\f05a"; + --fa--fa: "\f05a\f05a"; } + +.fa-info-circle { + --fa: "\f05a"; + --fa--fa: "\f05a\f05a"; } + +.fa-cloud-meatball { + --fa: "\f73b"; + --fa--fa: "\f73b\f73b"; } + +.fa-camera { + --fa: "\f030"; + --fa--fa: "\f030\f030"; } + +.fa-camera-alt { + --fa: "\f030"; + --fa--fa: "\f030\f030"; } + +.fa-square-virus { + --fa: "\e578"; + --fa--fa: "\e578\e578"; } + +.fa-meteor { + --fa: "\f753"; + --fa--fa: "\f753\f753"; } + +.fa-car-on { + --fa: "\e4dd"; + --fa--fa: "\e4dd\e4dd"; } + +.fa-sleigh { + --fa: "\f7cc"; + --fa--fa: "\f7cc\f7cc"; } + +.fa-arrow-down-1-9 { + --fa: "\f162"; + --fa--fa: "\f162\f162"; } + +.fa-sort-numeric-asc { + --fa: "\f162"; + --fa--fa: "\f162\f162"; } + +.fa-sort-numeric-down { + --fa: "\f162"; + --fa--fa: "\f162\f162"; } + +.fa-hand-holding-droplet { + --fa: "\f4c1"; + --fa--fa: "\f4c1\f4c1"; } + +.fa-hand-holding-water { + --fa: "\f4c1"; + --fa--fa: "\f4c1\f4c1"; } + +.fa-water { + --fa: "\f773"; + --fa--fa: "\f773\f773"; } + +.fa-calendar-check { + --fa: "\f274"; + --fa--fa: "\f274\f274"; } + +.fa-braille { + --fa: "\f2a1"; + --fa--fa: "\f2a1\f2a1"; } + +.fa-prescription-bottle-medical { + --fa: "\f486"; + --fa--fa: "\f486\f486"; } + +.fa-prescription-bottle-alt { + --fa: "\f486"; + --fa--fa: "\f486\f486"; } + +.fa-landmark { + --fa: "\f66f"; + --fa--fa: "\f66f\f66f"; } + +.fa-truck { + --fa: "\f0d1"; + --fa--fa: "\f0d1\f0d1"; } + +.fa-crosshairs { + --fa: "\f05b"; + --fa--fa: "\f05b\f05b"; } + +.fa-person-cane { + --fa: "\e53c"; + --fa--fa: "\e53c\e53c"; } + +.fa-tent { + --fa: "\e57d"; + --fa--fa: "\e57d\e57d"; } + +.fa-vest-patches { + --fa: "\e086"; + --fa--fa: "\e086\e086"; } + +.fa-check-double { + --fa: "\f560"; + --fa--fa: "\f560\f560"; } + +.fa-arrow-down-a-z { + --fa: "\f15d"; + --fa--fa: "\f15d\f15d"; } + +.fa-sort-alpha-asc { + --fa: "\f15d"; + --fa--fa: "\f15d\f15d"; } + +.fa-sort-alpha-down { + --fa: "\f15d"; + --fa--fa: "\f15d\f15d"; } + +.fa-money-bill-wheat { + --fa: "\e52a"; + --fa--fa: "\e52a\e52a"; } + +.fa-cookie { + --fa: "\f563"; + --fa--fa: "\f563\f563"; } + +.fa-arrow-rotate-left { + --fa: "\f0e2"; + --fa--fa: "\f0e2\f0e2"; } + +.fa-arrow-left-rotate { + --fa: "\f0e2"; + --fa--fa: "\f0e2\f0e2"; } + +.fa-arrow-rotate-back { + --fa: "\f0e2"; + --fa--fa: "\f0e2\f0e2"; } + +.fa-arrow-rotate-backward { + --fa: "\f0e2"; + --fa--fa: "\f0e2\f0e2"; } + +.fa-undo { + --fa: "\f0e2"; + --fa--fa: "\f0e2\f0e2"; } + +.fa-hard-drive { + --fa: "\f0a0"; + --fa--fa: "\f0a0\f0a0"; } + +.fa-hdd { + --fa: "\f0a0"; + --fa--fa: "\f0a0\f0a0"; } + +.fa-face-grin-squint-tears { + --fa: "\f586"; + --fa--fa: "\f586\f586"; } + +.fa-grin-squint-tears { + --fa: "\f586"; + --fa--fa: "\f586\f586"; } + +.fa-dumbbell { + --fa: "\f44b"; + --fa--fa: "\f44b\f44b"; } + +.fa-rectangle-list { + --fa: "\f022"; + --fa--fa: "\f022\f022"; } + +.fa-list-alt { + --fa: "\f022"; + --fa--fa: "\f022\f022"; } + +.fa-tarp-droplet { + --fa: "\e57c"; + --fa--fa: "\e57c\e57c"; } + +.fa-house-medical-circle-check { + --fa: "\e511"; + --fa--fa: "\e511\e511"; } + +.fa-person-skiing-nordic { + --fa: "\f7ca"; + --fa--fa: "\f7ca\f7ca"; } + +.fa-skiing-nordic { + --fa: "\f7ca"; + --fa--fa: "\f7ca\f7ca"; } + +.fa-calendar-plus { + --fa: "\f271"; + --fa--fa: "\f271\f271"; } + +.fa-plane-arrival { + --fa: "\f5af"; + --fa--fa: "\f5af\f5af"; } + +.fa-circle-left { + --fa: "\f359"; + --fa--fa: "\f359\f359"; } + +.fa-arrow-alt-circle-left { + --fa: "\f359"; + --fa--fa: "\f359\f359"; } + +.fa-train-subway { + --fa: "\f239"; + --fa--fa: "\f239\f239"; } + +.fa-subway { + --fa: "\f239"; + --fa--fa: "\f239\f239"; } + +.fa-chart-gantt { + --fa: "\e0e4"; + --fa--fa: "\e0e4\e0e4"; } + +.fa-indian-rupee-sign { + --fa: "\e1bc"; + --fa--fa: "\e1bc\e1bc"; } + +.fa-indian-rupee { + --fa: "\e1bc"; + --fa--fa: "\e1bc\e1bc"; } + +.fa-inr { + --fa: "\e1bc"; + --fa--fa: "\e1bc\e1bc"; } + +.fa-crop-simple { + --fa: "\f565"; + --fa--fa: "\f565\f565"; } + +.fa-crop-alt { + --fa: "\f565"; + --fa--fa: "\f565\f565"; } + +.fa-money-bill-1 { + --fa: "\f3d1"; + --fa--fa: "\f3d1\f3d1"; } + +.fa-money-bill-alt { + --fa: "\f3d1"; + --fa--fa: "\f3d1\f3d1"; } + +.fa-left-long { + --fa: "\f30a"; + --fa--fa: "\f30a\f30a"; } + +.fa-long-arrow-alt-left { + --fa: "\f30a"; + --fa--fa: "\f30a\f30a"; } + +.fa-dna { + --fa: "\f471"; + --fa--fa: "\f471\f471"; } + +.fa-virus-slash { + --fa: "\e075"; + --fa--fa: "\e075\e075"; } + +.fa-minus { + --fa: "\f068"; + --fa--fa: "\f068\f068"; } + +.fa-subtract { + --fa: "\f068"; + --fa--fa: "\f068\f068"; } + +.fa-chess { + --fa: "\f439"; + --fa--fa: "\f439\f439"; } + +.fa-arrow-left-long { + --fa: "\f177"; + --fa--fa: "\f177\f177"; } + +.fa-long-arrow-left { + --fa: "\f177"; + --fa--fa: "\f177\f177"; } + +.fa-plug-circle-check { + --fa: "\e55c"; + --fa--fa: "\e55c\e55c"; } + +.fa-street-view { + --fa: "\f21d"; + --fa--fa: "\f21d\f21d"; } + +.fa-franc-sign { + --fa: "\e18f"; + --fa--fa: "\e18f\e18f"; } + +.fa-volume-off { + --fa: "\f026"; + --fa--fa: "\f026\f026"; } + +.fa-hands-asl-interpreting { + --fa: "\f2a3"; + --fa--fa: "\f2a3\f2a3"; } + +.fa-american-sign-language-interpreting { + --fa: "\f2a3"; + --fa--fa: "\f2a3\f2a3"; } + +.fa-asl-interpreting { + --fa: "\f2a3"; + --fa--fa: "\f2a3\f2a3"; } + +.fa-hands-american-sign-language-interpreting { + --fa: "\f2a3"; + --fa--fa: "\f2a3\f2a3"; } + +.fa-gear { + --fa: "\f013"; + --fa--fa: "\f013\f013"; } + +.fa-cog { + --fa: "\f013"; + --fa--fa: "\f013\f013"; } + +.fa-droplet-slash { + --fa: "\f5c7"; + --fa--fa: "\f5c7\f5c7"; } + +.fa-tint-slash { + --fa: "\f5c7"; + --fa--fa: "\f5c7\f5c7"; } + +.fa-mosque { + --fa: "\f678"; + --fa--fa: "\f678\f678"; } + +.fa-mosquito { + --fa: "\e52b"; + --fa--fa: "\e52b\e52b"; } + +.fa-star-of-david { + --fa: "\f69a"; + --fa--fa: "\f69a\f69a"; } + +.fa-person-military-rifle { + --fa: "\e54b"; + --fa--fa: "\e54b\e54b"; } + +.fa-cart-shopping { + --fa: "\f07a"; + --fa--fa: "\f07a\f07a"; } + +.fa-shopping-cart { + --fa: "\f07a"; + --fa--fa: "\f07a\f07a"; } + +.fa-vials { + --fa: "\f493"; + --fa--fa: "\f493\f493"; } + +.fa-plug-circle-plus { + --fa: "\e55f"; + --fa--fa: "\e55f\e55f"; } + +.fa-place-of-worship { + --fa: "\f67f"; + --fa--fa: "\f67f\f67f"; } + +.fa-grip-vertical { + --fa: "\f58e"; + --fa--fa: "\f58e\f58e"; } + +.fa-hexagon-nodes { + --fa: "\e699"; + --fa--fa: "\e699\e699"; } + +.fa-arrow-turn-up { + --fa: "\f148"; + --fa--fa: "\f148\f148"; } + +.fa-level-up { + --fa: "\f148"; + --fa--fa: "\f148\f148"; } + +.fa-u { + --fa: "\55"; + --fa--fa: "\55\55"; } + +.fa-square-root-variable { + --fa: "\f698"; + --fa--fa: "\f698\f698"; } + +.fa-square-root-alt { + --fa: "\f698"; + --fa--fa: "\f698\f698"; } + +.fa-clock { + --fa: "\f017"; + --fa--fa: "\f017\f017"; } + +.fa-clock-four { + --fa: "\f017"; + --fa--fa: "\f017\f017"; } + +.fa-backward-step { + --fa: "\f048"; + --fa--fa: "\f048\f048"; } + +.fa-step-backward { + --fa: "\f048"; + --fa--fa: "\f048\f048"; } + +.fa-pallet { + --fa: "\f482"; + --fa--fa: "\f482\f482"; } + +.fa-faucet { + --fa: "\e005"; + --fa--fa: "\e005\e005"; } + +.fa-baseball-bat-ball { + --fa: "\f432"; + --fa--fa: "\f432\f432"; } + +.fa-s { + --fa: "\53"; + --fa--fa: "\53\53"; } + +.fa-timeline { + --fa: "\e29c"; + --fa--fa: "\e29c\e29c"; } + +.fa-keyboard { + --fa: "\f11c"; + --fa--fa: "\f11c\f11c"; } + +.fa-caret-down { + --fa: "\f0d7"; + --fa--fa: "\f0d7\f0d7"; } + +.fa-house-chimney-medical { + --fa: "\f7f2"; + --fa--fa: "\f7f2\f7f2"; } + +.fa-clinic-medical { + --fa: "\f7f2"; + --fa--fa: "\f7f2\f7f2"; } + +.fa-temperature-three-quarters { + --fa: "\f2c8"; + --fa--fa: "\f2c8\f2c8"; } + +.fa-temperature-3 { + --fa: "\f2c8"; + --fa--fa: "\f2c8\f2c8"; } + +.fa-thermometer-3 { + --fa: "\f2c8"; + --fa--fa: "\f2c8\f2c8"; } + +.fa-thermometer-three-quarters { + --fa: "\f2c8"; + --fa--fa: "\f2c8\f2c8"; } + +.fa-mobile-screen { + --fa: "\f3cf"; + --fa--fa: "\f3cf\f3cf"; } + +.fa-mobile-android-alt { + --fa: "\f3cf"; + --fa--fa: "\f3cf\f3cf"; } + +.fa-plane-up { + --fa: "\e22d"; + --fa--fa: "\e22d\e22d"; } + +.fa-piggy-bank { + --fa: "\f4d3"; + --fa--fa: "\f4d3\f4d3"; } + +.fa-battery-half { + --fa: "\f242"; + --fa--fa: "\f242\f242"; } + +.fa-battery-3 { + --fa: "\f242"; + --fa--fa: "\f242\f242"; } + +.fa-mountain-city { + --fa: "\e52e"; + --fa--fa: "\e52e\e52e"; } + +.fa-coins { + --fa: "\f51e"; + --fa--fa: "\f51e\f51e"; } + +.fa-khanda { + --fa: "\f66d"; + --fa--fa: "\f66d\f66d"; } + +.fa-sliders { + --fa: "\f1de"; + --fa--fa: "\f1de\f1de"; } + +.fa-sliders-h { + --fa: "\f1de"; + --fa--fa: "\f1de\f1de"; } + +.fa-folder-tree { + --fa: "\f802"; + --fa--fa: "\f802\f802"; } + +.fa-network-wired { + --fa: "\f6ff"; + --fa--fa: "\f6ff\f6ff"; } + +.fa-map-pin { + --fa: "\f276"; + --fa--fa: "\f276\f276"; } + +.fa-hamsa { + --fa: "\f665"; + --fa--fa: "\f665\f665"; } + +.fa-cent-sign { + --fa: "\e3f5"; + --fa--fa: "\e3f5\e3f5"; } + +.fa-flask { + --fa: "\f0c3"; + --fa--fa: "\f0c3\f0c3"; } + +.fa-person-pregnant { + --fa: "\e31e"; + --fa--fa: "\e31e\e31e"; } + +.fa-wand-sparkles { + --fa: "\f72b"; + --fa--fa: "\f72b\f72b"; } + +.fa-ellipsis-vertical { + --fa: "\f142"; + --fa--fa: "\f142\f142"; } + +.fa-ellipsis-v { + --fa: "\f142"; + --fa--fa: "\f142\f142"; } + +.fa-ticket { + --fa: "\f145"; + --fa--fa: "\f145\f145"; } + +.fa-power-off { + --fa: "\f011"; + --fa--fa: "\f011\f011"; } + +.fa-right-long { + --fa: "\f30b"; + --fa--fa: "\f30b\f30b"; } + +.fa-long-arrow-alt-right { + --fa: "\f30b"; + --fa--fa: "\f30b\f30b"; } + +.fa-flag-usa { + --fa: "\f74d"; + --fa--fa: "\f74d\f74d"; } + +.fa-laptop-file { + --fa: "\e51d"; + --fa--fa: "\e51d\e51d"; } + +.fa-tty { + --fa: "\f1e4"; + --fa--fa: "\f1e4\f1e4"; } + +.fa-teletype { + --fa: "\f1e4"; + --fa--fa: "\f1e4\f1e4"; } + +.fa-diagram-next { + --fa: "\e476"; + --fa--fa: "\e476\e476"; } + +.fa-person-rifle { + --fa: "\e54e"; + --fa--fa: "\e54e\e54e"; } + +.fa-house-medical-circle-exclamation { + --fa: "\e512"; + --fa--fa: "\e512\e512"; } + +.fa-closed-captioning { + --fa: "\f20a"; + --fa--fa: "\f20a\f20a"; } + +.fa-person-hiking { + --fa: "\f6ec"; + --fa--fa: "\f6ec\f6ec"; } + +.fa-hiking { + --fa: "\f6ec"; + --fa--fa: "\f6ec\f6ec"; } + +.fa-venus-double { + --fa: "\f226"; + --fa--fa: "\f226\f226"; } + +.fa-images { + --fa: "\f302"; + --fa--fa: "\f302\f302"; } + +.fa-calculator { + --fa: "\f1ec"; + --fa--fa: "\f1ec\f1ec"; } + +.fa-people-pulling { + --fa: "\e535"; + --fa--fa: "\e535\e535"; } + +.fa-n { + --fa: "\4e"; + --fa--fa: "\4e\4e"; } + +.fa-cable-car { + --fa: "\f7da"; + --fa--fa: "\f7da\f7da"; } + +.fa-tram { + --fa: "\f7da"; + --fa--fa: "\f7da\f7da"; } + +.fa-cloud-rain { + --fa: "\f73d"; + --fa--fa: "\f73d\f73d"; } + +.fa-building-circle-xmark { + --fa: "\e4d4"; + --fa--fa: "\e4d4\e4d4"; } + +.fa-ship { + --fa: "\f21a"; + --fa--fa: "\f21a\f21a"; } + +.fa-arrows-down-to-line { + --fa: "\e4b8"; + --fa--fa: "\e4b8\e4b8"; } + +.fa-download { + --fa: "\f019"; + --fa--fa: "\f019\f019"; } + +.fa-face-grin { + --fa: "\f580"; + --fa--fa: "\f580\f580"; } + +.fa-grin { + --fa: "\f580"; + --fa--fa: "\f580\f580"; } + +.fa-delete-left { + --fa: "\f55a"; + --fa--fa: "\f55a\f55a"; } + +.fa-backspace { + --fa: "\f55a"; + --fa--fa: "\f55a\f55a"; } + +.fa-eye-dropper { + --fa: "\f1fb"; + --fa--fa: "\f1fb\f1fb"; } + +.fa-eye-dropper-empty { + --fa: "\f1fb"; + --fa--fa: "\f1fb\f1fb"; } + +.fa-eyedropper { + --fa: "\f1fb"; + --fa--fa: "\f1fb\f1fb"; } + +.fa-file-circle-check { + --fa: "\e5a0"; + --fa--fa: "\e5a0\e5a0"; } + +.fa-forward { + --fa: "\f04e"; + --fa--fa: "\f04e\f04e"; } + +.fa-mobile { + --fa: "\f3ce"; + --fa--fa: "\f3ce\f3ce"; } + +.fa-mobile-android { + --fa: "\f3ce"; + --fa--fa: "\f3ce\f3ce"; } + +.fa-mobile-phone { + --fa: "\f3ce"; + --fa--fa: "\f3ce\f3ce"; } + +.fa-face-meh { + --fa: "\f11a"; + --fa--fa: "\f11a\f11a"; } + +.fa-meh { + --fa: "\f11a"; + --fa--fa: "\f11a\f11a"; } + +.fa-align-center { + --fa: "\f037"; + --fa--fa: "\f037\f037"; } + +.fa-book-skull { + --fa: "\f6b7"; + --fa--fa: "\f6b7\f6b7"; } + +.fa-book-dead { + --fa: "\f6b7"; + --fa--fa: "\f6b7\f6b7"; } + +.fa-id-card { + --fa: "\f2c2"; + --fa--fa: "\f2c2\f2c2"; } + +.fa-drivers-license { + --fa: "\f2c2"; + --fa--fa: "\f2c2\f2c2"; } + +.fa-outdent { + --fa: "\f03b"; + --fa--fa: "\f03b\f03b"; } + +.fa-dedent { + --fa: "\f03b"; + --fa--fa: "\f03b\f03b"; } + +.fa-heart-circle-exclamation { + --fa: "\e4fe"; + --fa--fa: "\e4fe\e4fe"; } + +.fa-house { + --fa: "\f015"; + --fa--fa: "\f015\f015"; } + +.fa-home { + --fa: "\f015"; + --fa--fa: "\f015\f015"; } + +.fa-home-alt { + --fa: "\f015"; + --fa--fa: "\f015\f015"; } + +.fa-home-lg-alt { + --fa: "\f015"; + --fa--fa: "\f015\f015"; } + +.fa-calendar-week { + --fa: "\f784"; + --fa--fa: "\f784\f784"; } + +.fa-laptop-medical { + --fa: "\f812"; + --fa--fa: "\f812\f812"; } + +.fa-b { + --fa: "\42"; + --fa--fa: "\42\42"; } + +.fa-file-medical { + --fa: "\f477"; + --fa--fa: "\f477\f477"; } + +.fa-dice-one { + --fa: "\f525"; + --fa--fa: "\f525\f525"; } + +.fa-kiwi-bird { + --fa: "\f535"; + --fa--fa: "\f535\f535"; } + +.fa-arrow-right-arrow-left { + --fa: "\f0ec"; + --fa--fa: "\f0ec\f0ec"; } + +.fa-exchange { + --fa: "\f0ec"; + --fa--fa: "\f0ec\f0ec"; } + +.fa-rotate-right { + --fa: "\f2f9"; + --fa--fa: "\f2f9\f2f9"; } + +.fa-redo-alt { + --fa: "\f2f9"; + --fa--fa: "\f2f9\f2f9"; } + +.fa-rotate-forward { + --fa: "\f2f9"; + --fa--fa: "\f2f9\f2f9"; } + +.fa-utensils { + --fa: "\f2e7"; + --fa--fa: "\f2e7\f2e7"; } + +.fa-cutlery { + --fa: "\f2e7"; + --fa--fa: "\f2e7\f2e7"; } + +.fa-arrow-up-wide-short { + --fa: "\f161"; + --fa--fa: "\f161\f161"; } + +.fa-sort-amount-up { + --fa: "\f161"; + --fa--fa: "\f161\f161"; } + +.fa-mill-sign { + --fa: "\e1ed"; + --fa--fa: "\e1ed\e1ed"; } + +.fa-bowl-rice { + --fa: "\e2eb"; + --fa--fa: "\e2eb\e2eb"; } + +.fa-skull { + --fa: "\f54c"; + --fa--fa: "\f54c\f54c"; } + +.fa-tower-broadcast { + --fa: "\f519"; + --fa--fa: "\f519\f519"; } + +.fa-broadcast-tower { + --fa: "\f519"; + --fa--fa: "\f519\f519"; } + +.fa-truck-pickup { + --fa: "\f63c"; + --fa--fa: "\f63c\f63c"; } + +.fa-up-long { + --fa: "\f30c"; + --fa--fa: "\f30c\f30c"; } + +.fa-long-arrow-alt-up { + --fa: "\f30c"; + --fa--fa: "\f30c\f30c"; } + +.fa-stop { + --fa: "\f04d"; + --fa--fa: "\f04d\f04d"; } + +.fa-code-merge { + --fa: "\f387"; + --fa--fa: "\f387\f387"; } + +.fa-upload { + --fa: "\f093"; + --fa--fa: "\f093\f093"; } + +.fa-hurricane { + --fa: "\f751"; + --fa--fa: "\f751\f751"; } + +.fa-mound { + --fa: "\e52d"; + --fa--fa: "\e52d\e52d"; } + +.fa-toilet-portable { + --fa: "\e583"; + --fa--fa: "\e583\e583"; } + +.fa-compact-disc { + --fa: "\f51f"; + --fa--fa: "\f51f\f51f"; } + +.fa-file-arrow-down { + --fa: "\f56d"; + --fa--fa: "\f56d\f56d"; } + +.fa-file-download { + --fa: "\f56d"; + --fa--fa: "\f56d\f56d"; } + +.fa-caravan { + --fa: "\f8ff"; + --fa--fa: "\f8ff\f8ff"; } + +.fa-shield-cat { + --fa: "\e572"; + --fa--fa: "\e572\e572"; } + +.fa-bolt { + --fa: "\f0e7"; + --fa--fa: "\f0e7\f0e7"; } + +.fa-zap { + --fa: "\f0e7"; + --fa--fa: "\f0e7\f0e7"; } + +.fa-glass-water { + --fa: "\e4f4"; + --fa--fa: "\e4f4\e4f4"; } + +.fa-oil-well { + --fa: "\e532"; + --fa--fa: "\e532\e532"; } + +.fa-vault { + --fa: "\e2c5"; + --fa--fa: "\e2c5\e2c5"; } + +.fa-mars { + --fa: "\f222"; + --fa--fa: "\f222\f222"; } + +.fa-toilet { + --fa: "\f7d8"; + --fa--fa: "\f7d8\f7d8"; } + +.fa-plane-circle-xmark { + --fa: "\e557"; + --fa--fa: "\e557\e557"; } + +.fa-yen-sign { + --fa: "\f157"; + --fa--fa: "\f157\f157"; } + +.fa-cny { + --fa: "\f157"; + --fa--fa: "\f157\f157"; } + +.fa-jpy { + --fa: "\f157"; + --fa--fa: "\f157\f157"; } + +.fa-rmb { + --fa: "\f157"; + --fa--fa: "\f157\f157"; } + +.fa-yen { + --fa: "\f157"; + --fa--fa: "\f157\f157"; } + +.fa-ruble-sign { + --fa: "\f158"; + --fa--fa: "\f158\f158"; } + +.fa-rouble { + --fa: "\f158"; + --fa--fa: "\f158\f158"; } + +.fa-rub { + --fa: "\f158"; + --fa--fa: "\f158\f158"; } + +.fa-ruble { + --fa: "\f158"; + --fa--fa: "\f158\f158"; } + +.fa-sun { + --fa: "\f185"; + --fa--fa: "\f185\f185"; } + +.fa-guitar { + --fa: "\f7a6"; + --fa--fa: "\f7a6\f7a6"; } + +.fa-face-laugh-wink { + --fa: "\f59c"; + --fa--fa: "\f59c\f59c"; } + +.fa-laugh-wink { + --fa: "\f59c"; + --fa--fa: "\f59c\f59c"; } + +.fa-horse-head { + --fa: "\f7ab"; + --fa--fa: "\f7ab\f7ab"; } + +.fa-bore-hole { + --fa: "\e4c3"; + --fa--fa: "\e4c3\e4c3"; } + +.fa-industry { + --fa: "\f275"; + --fa--fa: "\f275\f275"; } + +.fa-circle-down { + --fa: "\f358"; + --fa--fa: "\f358\f358"; } + +.fa-arrow-alt-circle-down { + --fa: "\f358"; + --fa--fa: "\f358\f358"; } + +.fa-arrows-turn-to-dots { + --fa: "\e4c1"; + --fa--fa: "\e4c1\e4c1"; } + +.fa-florin-sign { + --fa: "\e184"; + --fa--fa: "\e184\e184"; } + +.fa-arrow-down-short-wide { + --fa: "\f884"; + --fa--fa: "\f884\f884"; } + +.fa-sort-amount-desc { + --fa: "\f884"; + --fa--fa: "\f884\f884"; } + +.fa-sort-amount-down-alt { + --fa: "\f884"; + --fa--fa: "\f884\f884"; } + +.fa-less-than { + --fa: "\3c"; + --fa--fa: "\3c\3c"; } + +.fa-angle-down { + --fa: "\f107"; + --fa--fa: "\f107\f107"; } + +.fa-car-tunnel { + --fa: "\e4de"; + --fa--fa: "\e4de\e4de"; } + +.fa-head-side-cough { + --fa: "\e061"; + --fa--fa: "\e061\e061"; } + +.fa-grip-lines { + --fa: "\f7a4"; + --fa--fa: "\f7a4\f7a4"; } + +.fa-thumbs-down { + --fa: "\f165"; + --fa--fa: "\f165\f165"; } + +.fa-user-lock { + --fa: "\f502"; + --fa--fa: "\f502\f502"; } + +.fa-arrow-right-long { + --fa: "\f178"; + --fa--fa: "\f178\f178"; } + +.fa-long-arrow-right { + --fa: "\f178"; + --fa--fa: "\f178\f178"; } + +.fa-anchor-circle-xmark { + --fa: "\e4ac"; + --fa--fa: "\e4ac\e4ac"; } + +.fa-ellipsis { + --fa: "\f141"; + --fa--fa: "\f141\f141"; } + +.fa-ellipsis-h { + --fa: "\f141"; + --fa--fa: "\f141\f141"; } + +.fa-chess-pawn { + --fa: "\f443"; + --fa--fa: "\f443\f443"; } + +.fa-kit-medical { + --fa: "\f479"; + --fa--fa: "\f479\f479"; } + +.fa-first-aid { + --fa: "\f479"; + --fa--fa: "\f479\f479"; } + +.fa-person-through-window { + --fa: "\e5a9"; + --fa--fa: "\e5a9\e5a9"; } + +.fa-toolbox { + --fa: "\f552"; + --fa--fa: "\f552\f552"; } + +.fa-hands-holding-circle { + --fa: "\e4fb"; + --fa--fa: "\e4fb\e4fb"; } + +.fa-bug { + --fa: "\f188"; + --fa--fa: "\f188\f188"; } + +.fa-credit-card { + --fa: "\f09d"; + --fa--fa: "\f09d\f09d"; } + +.fa-credit-card-alt { + --fa: "\f09d"; + --fa--fa: "\f09d\f09d"; } + +.fa-car { + --fa: "\f1b9"; + --fa--fa: "\f1b9\f1b9"; } + +.fa-automobile { + --fa: "\f1b9"; + --fa--fa: "\f1b9\f1b9"; } + +.fa-hand-holding-hand { + --fa: "\e4f7"; + --fa--fa: "\e4f7\e4f7"; } + +.fa-book-open-reader { + --fa: "\f5da"; + --fa--fa: "\f5da\f5da"; } + +.fa-book-reader { + --fa: "\f5da"; + --fa--fa: "\f5da\f5da"; } + +.fa-mountain-sun { + --fa: "\e52f"; + --fa--fa: "\e52f\e52f"; } + +.fa-arrows-left-right-to-line { + --fa: "\e4ba"; + --fa--fa: "\e4ba\e4ba"; } + +.fa-dice-d20 { + --fa: "\f6cf"; + --fa--fa: "\f6cf\f6cf"; } + +.fa-truck-droplet { + --fa: "\e58c"; + --fa--fa: "\e58c\e58c"; } + +.fa-file-circle-xmark { + --fa: "\e5a1"; + --fa--fa: "\e5a1\e5a1"; } + +.fa-temperature-arrow-up { + --fa: "\e040"; + --fa--fa: "\e040\e040"; } + +.fa-temperature-up { + --fa: "\e040"; + --fa--fa: "\e040\e040"; } + +.fa-medal { + --fa: "\f5a2"; + --fa--fa: "\f5a2\f5a2"; } + +.fa-bed { + --fa: "\f236"; + --fa--fa: "\f236\f236"; } + +.fa-square-h { + --fa: "\f0fd"; + --fa--fa: "\f0fd\f0fd"; } + +.fa-h-square { + --fa: "\f0fd"; + --fa--fa: "\f0fd\f0fd"; } + +.fa-podcast { + --fa: "\f2ce"; + --fa--fa: "\f2ce\f2ce"; } + +.fa-temperature-full { + --fa: "\f2c7"; + --fa--fa: "\f2c7\f2c7"; } + +.fa-temperature-4 { + --fa: "\f2c7"; + --fa--fa: "\f2c7\f2c7"; } + +.fa-thermometer-4 { + --fa: "\f2c7"; + --fa--fa: "\f2c7\f2c7"; } + +.fa-thermometer-full { + --fa: "\f2c7"; + --fa--fa: "\f2c7\f2c7"; } + +.fa-bell { + --fa: "\f0f3"; + --fa--fa: "\f0f3\f0f3"; } + +.fa-superscript { + --fa: "\f12b"; + --fa--fa: "\f12b\f12b"; } + +.fa-plug-circle-xmark { + --fa: "\e560"; + --fa--fa: "\e560\e560"; } + +.fa-star-of-life { + --fa: "\f621"; + --fa--fa: "\f621\f621"; } + +.fa-phone-slash { + --fa: "\f3dd"; + --fa--fa: "\f3dd\f3dd"; } + +.fa-paint-roller { + --fa: "\f5aa"; + --fa--fa: "\f5aa\f5aa"; } + +.fa-handshake-angle { + --fa: "\f4c4"; + --fa--fa: "\f4c4\f4c4"; } + +.fa-hands-helping { + --fa: "\f4c4"; + --fa--fa: "\f4c4\f4c4"; } + +.fa-location-dot { + --fa: "\f3c5"; + --fa--fa: "\f3c5\f3c5"; } + +.fa-map-marker-alt { + --fa: "\f3c5"; + --fa--fa: "\f3c5\f3c5"; } + +.fa-file { + --fa: "\f15b"; + --fa--fa: "\f15b\f15b"; } + +.fa-greater-than { + --fa: "\3e"; + --fa--fa: "\3e\3e"; } + +.fa-person-swimming { + --fa: "\f5c4"; + --fa--fa: "\f5c4\f5c4"; } + +.fa-swimmer { + --fa: "\f5c4"; + --fa--fa: "\f5c4\f5c4"; } + +.fa-arrow-down { + --fa: "\f063"; + --fa--fa: "\f063\f063"; } + +.fa-droplet { + --fa: "\f043"; + --fa--fa: "\f043\f043"; } + +.fa-tint { + --fa: "\f043"; + --fa--fa: "\f043\f043"; } + +.fa-eraser { + --fa: "\f12d"; + --fa--fa: "\f12d\f12d"; } + +.fa-earth-americas { + --fa: "\f57d"; + --fa--fa: "\f57d\f57d"; } + +.fa-earth { + --fa: "\f57d"; + --fa--fa: "\f57d\f57d"; } + +.fa-earth-america { + --fa: "\f57d"; + --fa--fa: "\f57d\f57d"; } + +.fa-globe-americas { + --fa: "\f57d"; + --fa--fa: "\f57d\f57d"; } + +.fa-person-burst { + --fa: "\e53b"; + --fa--fa: "\e53b\e53b"; } + +.fa-dove { + --fa: "\f4ba"; + --fa--fa: "\f4ba\f4ba"; } + +.fa-battery-empty { + --fa: "\f244"; + --fa--fa: "\f244\f244"; } + +.fa-battery-0 { + --fa: "\f244"; + --fa--fa: "\f244\f244"; } + +.fa-socks { + --fa: "\f696"; + --fa--fa: "\f696\f696"; } + +.fa-inbox { + --fa: "\f01c"; + --fa--fa: "\f01c\f01c"; } + +.fa-section { + --fa: "\e447"; + --fa--fa: "\e447\e447"; } + +.fa-gauge-high { + --fa: "\f625"; + --fa--fa: "\f625\f625"; } + +.fa-tachometer-alt { + --fa: "\f625"; + --fa--fa: "\f625\f625"; } + +.fa-tachometer-alt-fast { + --fa: "\f625"; + --fa--fa: "\f625\f625"; } + +.fa-envelope-open-text { + --fa: "\f658"; + --fa--fa: "\f658\f658"; } + +.fa-hospital { + --fa: "\f0f8"; + --fa--fa: "\f0f8\f0f8"; } + +.fa-hospital-alt { + --fa: "\f0f8"; + --fa--fa: "\f0f8\f0f8"; } + +.fa-hospital-wide { + --fa: "\f0f8"; + --fa--fa: "\f0f8\f0f8"; } + +.fa-wine-bottle { + --fa: "\f72f"; + --fa--fa: "\f72f\f72f"; } + +.fa-chess-rook { + --fa: "\f447"; + --fa--fa: "\f447\f447"; } + +.fa-bars-staggered { + --fa: "\f550"; + --fa--fa: "\f550\f550"; } + +.fa-reorder { + --fa: "\f550"; + --fa--fa: "\f550\f550"; } + +.fa-stream { + --fa: "\f550"; + --fa--fa: "\f550\f550"; } + +.fa-dharmachakra { + --fa: "\f655"; + --fa--fa: "\f655\f655"; } + +.fa-hotdog { + --fa: "\f80f"; + --fa--fa: "\f80f\f80f"; } + +.fa-person-walking-with-cane { + --fa: "\f29d"; + --fa--fa: "\f29d\f29d"; } + +.fa-blind { + --fa: "\f29d"; + --fa--fa: "\f29d\f29d"; } + +.fa-drum { + --fa: "\f569"; + --fa--fa: "\f569\f569"; } + +.fa-ice-cream { + --fa: "\f810"; + --fa--fa: "\f810\f810"; } + +.fa-heart-circle-bolt { + --fa: "\e4fc"; + --fa--fa: "\e4fc\e4fc"; } + +.fa-fax { + --fa: "\f1ac"; + --fa--fa: "\f1ac\f1ac"; } + +.fa-paragraph { + --fa: "\f1dd"; + --fa--fa: "\f1dd\f1dd"; } + +.fa-check-to-slot { + --fa: "\f772"; + --fa--fa: "\f772\f772"; } + +.fa-vote-yea { + --fa: "\f772"; + --fa--fa: "\f772\f772"; } + +.fa-star-half { + --fa: "\f089"; + --fa--fa: "\f089\f089"; } + +.fa-boxes-stacked { + --fa: "\f468"; + --fa--fa: "\f468\f468"; } + +.fa-boxes { + --fa: "\f468"; + --fa--fa: "\f468\f468"; } + +.fa-boxes-alt { + --fa: "\f468"; + --fa--fa: "\f468\f468"; } + +.fa-link { + --fa: "\f0c1"; + --fa--fa: "\f0c1\f0c1"; } + +.fa-chain { + --fa: "\f0c1"; + --fa--fa: "\f0c1\f0c1"; } + +.fa-ear-listen { + --fa: "\f2a2"; + --fa--fa: "\f2a2\f2a2"; } + +.fa-assistive-listening-systems { + --fa: "\f2a2"; + --fa--fa: "\f2a2\f2a2"; } + +.fa-tree-city { + --fa: "\e587"; + --fa--fa: "\e587\e587"; } + +.fa-play { + --fa: "\f04b"; + --fa--fa: "\f04b\f04b"; } + +.fa-font { + --fa: "\f031"; + --fa--fa: "\f031\f031"; } + +.fa-table-cells-row-lock { + --fa: "\e67a"; + --fa--fa: "\e67a\e67a"; } + +.fa-rupiah-sign { + --fa: "\e23d"; + --fa--fa: "\e23d\e23d"; } + +.fa-magnifying-glass { + --fa: "\f002"; + --fa--fa: "\f002\f002"; } + +.fa-search { + --fa: "\f002"; + --fa--fa: "\f002\f002"; } + +.fa-table-tennis-paddle-ball { + --fa: "\f45d"; + --fa--fa: "\f45d\f45d"; } + +.fa-ping-pong-paddle-ball { + --fa: "\f45d"; + --fa--fa: "\f45d\f45d"; } + +.fa-table-tennis { + --fa: "\f45d"; + --fa--fa: "\f45d\f45d"; } + +.fa-person-dots-from-line { + --fa: "\f470"; + --fa--fa: "\f470\f470"; } + +.fa-diagnoses { + --fa: "\f470"; + --fa--fa: "\f470\f470"; } + +.fa-trash-can-arrow-up { + --fa: "\f82a"; + --fa--fa: "\f82a\f82a"; } + +.fa-trash-restore-alt { + --fa: "\f82a"; + --fa--fa: "\f82a\f82a"; } + +.fa-naira-sign { + --fa: "\e1f6"; + --fa--fa: "\e1f6\e1f6"; } + +.fa-cart-arrow-down { + --fa: "\f218"; + --fa--fa: "\f218\f218"; } + +.fa-walkie-talkie { + --fa: "\f8ef"; + --fa--fa: "\f8ef\f8ef"; } + +.fa-file-pen { + --fa: "\f31c"; + --fa--fa: "\f31c\f31c"; } + +.fa-file-edit { + --fa: "\f31c"; + --fa--fa: "\f31c\f31c"; } + +.fa-receipt { + --fa: "\f543"; + --fa--fa: "\f543\f543"; } + +.fa-square-pen { + --fa: "\f14b"; + --fa--fa: "\f14b\f14b"; } + +.fa-pen-square { + --fa: "\f14b"; + --fa--fa: "\f14b\f14b"; } + +.fa-pencil-square { + --fa: "\f14b"; + --fa--fa: "\f14b\f14b"; } + +.fa-suitcase-rolling { + --fa: "\f5c1"; + --fa--fa: "\f5c1\f5c1"; } + +.fa-person-circle-exclamation { + --fa: "\e53f"; + --fa--fa: "\e53f\e53f"; } + +.fa-chevron-down { + --fa: "\f078"; + --fa--fa: "\f078\f078"; } + +.fa-battery-full { + --fa: "\f240"; + --fa--fa: "\f240\f240"; } + +.fa-battery { + --fa: "\f240"; + --fa--fa: "\f240\f240"; } + +.fa-battery-5 { + --fa: "\f240"; + --fa--fa: "\f240\f240"; } + +.fa-skull-crossbones { + --fa: "\f714"; + --fa--fa: "\f714\f714"; } + +.fa-code-compare { + --fa: "\e13a"; + --fa--fa: "\e13a\e13a"; } + +.fa-list-ul { + --fa: "\f0ca"; + --fa--fa: "\f0ca\f0ca"; } + +.fa-list-dots { + --fa: "\f0ca"; + --fa--fa: "\f0ca\f0ca"; } + +.fa-school-lock { + --fa: "\e56f"; + --fa--fa: "\e56f\e56f"; } + +.fa-tower-cell { + --fa: "\e585"; + --fa--fa: "\e585\e585"; } + +.fa-down-long { + --fa: "\f309"; + --fa--fa: "\f309\f309"; } + +.fa-long-arrow-alt-down { + --fa: "\f309"; + --fa--fa: "\f309\f309"; } + +.fa-ranking-star { + --fa: "\e561"; + --fa--fa: "\e561\e561"; } + +.fa-chess-king { + --fa: "\f43f"; + --fa--fa: "\f43f\f43f"; } + +.fa-person-harassing { + --fa: "\e549"; + --fa--fa: "\e549\e549"; } + +.fa-brazilian-real-sign { + --fa: "\e46c"; + --fa--fa: "\e46c\e46c"; } + +.fa-landmark-dome { + --fa: "\f752"; + --fa--fa: "\f752\f752"; } + +.fa-landmark-alt { + --fa: "\f752"; + --fa--fa: "\f752\f752"; } + +.fa-arrow-up { + --fa: "\f062"; + --fa--fa: "\f062\f062"; } + +.fa-tv { + --fa: "\f26c"; + --fa--fa: "\f26c\f26c"; } + +.fa-television { + --fa: "\f26c"; + --fa--fa: "\f26c\f26c"; } + +.fa-tv-alt { + --fa: "\f26c"; + --fa--fa: "\f26c\f26c"; } + +.fa-shrimp { + --fa: "\e448"; + --fa--fa: "\e448\e448"; } + +.fa-list-check { + --fa: "\f0ae"; + --fa--fa: "\f0ae\f0ae"; } + +.fa-tasks { + --fa: "\f0ae"; + --fa--fa: "\f0ae\f0ae"; } + +.fa-jug-detergent { + --fa: "\e519"; + --fa--fa: "\e519\e519"; } + +.fa-circle-user { + --fa: "\f2bd"; + --fa--fa: "\f2bd\f2bd"; } + +.fa-user-circle { + --fa: "\f2bd"; + --fa--fa: "\f2bd\f2bd"; } + +.fa-user-shield { + --fa: "\f505"; + --fa--fa: "\f505\f505"; } + +.fa-wind { + --fa: "\f72e"; + --fa--fa: "\f72e\f72e"; } + +.fa-car-burst { + --fa: "\f5e1"; + --fa--fa: "\f5e1\f5e1"; } + +.fa-car-crash { + --fa: "\f5e1"; + --fa--fa: "\f5e1\f5e1"; } + +.fa-y { + --fa: "\59"; + --fa--fa: "\59\59"; } + +.fa-person-snowboarding { + --fa: "\f7ce"; + --fa--fa: "\f7ce\f7ce"; } + +.fa-snowboarding { + --fa: "\f7ce"; + --fa--fa: "\f7ce\f7ce"; } + +.fa-truck-fast { + --fa: "\f48b"; + --fa--fa: "\f48b\f48b"; } + +.fa-shipping-fast { + --fa: "\f48b"; + --fa--fa: "\f48b\f48b"; } + +.fa-fish { + --fa: "\f578"; + --fa--fa: "\f578\f578"; } + +.fa-user-graduate { + --fa: "\f501"; + --fa--fa: "\f501\f501"; } + +.fa-circle-half-stroke { + --fa: "\f042"; + --fa--fa: "\f042\f042"; } + +.fa-adjust { + --fa: "\f042"; + --fa--fa: "\f042\f042"; } + +.fa-clapperboard { + --fa: "\e131"; + --fa--fa: "\e131\e131"; } + +.fa-circle-radiation { + --fa: "\f7ba"; + --fa--fa: "\f7ba\f7ba"; } + +.fa-radiation-alt { + --fa: "\f7ba"; + --fa--fa: "\f7ba\f7ba"; } + +.fa-baseball { + --fa: "\f433"; + --fa--fa: "\f433\f433"; } + +.fa-baseball-ball { + --fa: "\f433"; + --fa--fa: "\f433\f433"; } + +.fa-jet-fighter-up { + --fa: "\e518"; + --fa--fa: "\e518\e518"; } + +.fa-diagram-project { + --fa: "\f542"; + --fa--fa: "\f542\f542"; } + +.fa-project-diagram { + --fa: "\f542"; + --fa--fa: "\f542\f542"; } + +.fa-copy { + --fa: "\f0c5"; + --fa--fa: "\f0c5\f0c5"; } + +.fa-volume-xmark { + --fa: "\f6a9"; + --fa--fa: "\f6a9\f6a9"; } + +.fa-volume-mute { + --fa: "\f6a9"; + --fa--fa: "\f6a9\f6a9"; } + +.fa-volume-times { + --fa: "\f6a9"; + --fa--fa: "\f6a9\f6a9"; } + +.fa-hand-sparkles { + --fa: "\e05d"; + --fa--fa: "\e05d\e05d"; } + +.fa-grip { + --fa: "\f58d"; + --fa--fa: "\f58d\f58d"; } + +.fa-grip-horizontal { + --fa: "\f58d"; + --fa--fa: "\f58d\f58d"; } + +.fa-share-from-square { + --fa: "\f14d"; + --fa--fa: "\f14d\f14d"; } + +.fa-share-square { + --fa: "\f14d"; + --fa--fa: "\f14d\f14d"; } + +.fa-child-combatant { + --fa: "\e4e0"; + --fa--fa: "\e4e0\e4e0"; } + +.fa-child-rifle { + --fa: "\e4e0"; + --fa--fa: "\e4e0\e4e0"; } + +.fa-gun { + --fa: "\e19b"; + --fa--fa: "\e19b\e19b"; } + +.fa-square-phone { + --fa: "\f098"; + --fa--fa: "\f098\f098"; } + +.fa-phone-square { + --fa: "\f098"; + --fa--fa: "\f098\f098"; } + +.fa-plus { + --fa: "\2b"; + --fa--fa: "\2b\2b"; } + +.fa-add { + --fa: "\2b"; + --fa--fa: "\2b\2b"; } + +.fa-expand { + --fa: "\f065"; + --fa--fa: "\f065\f065"; } + +.fa-computer { + --fa: "\e4e5"; + --fa--fa: "\e4e5\e4e5"; } + +.fa-xmark { + --fa: "\f00d"; + --fa--fa: "\f00d\f00d"; } + +.fa-close { + --fa: "\f00d"; + --fa--fa: "\f00d\f00d"; } + +.fa-multiply { + --fa: "\f00d"; + --fa--fa: "\f00d\f00d"; } + +.fa-remove { + --fa: "\f00d"; + --fa--fa: "\f00d\f00d"; } + +.fa-times { + --fa: "\f00d"; + --fa--fa: "\f00d\f00d"; } + +.fa-arrows-up-down-left-right { + --fa: "\f047"; + --fa--fa: "\f047\f047"; } + +.fa-arrows { + --fa: "\f047"; + --fa--fa: "\f047\f047"; } + +.fa-chalkboard-user { + --fa: "\f51c"; + --fa--fa: "\f51c\f51c"; } + +.fa-chalkboard-teacher { + --fa: "\f51c"; + --fa--fa: "\f51c\f51c"; } + +.fa-peso-sign { + --fa: "\e222"; + --fa--fa: "\e222\e222"; } + +.fa-building-shield { + --fa: "\e4d8"; + --fa--fa: "\e4d8\e4d8"; } + +.fa-baby { + --fa: "\f77c"; + --fa--fa: "\f77c\f77c"; } + +.fa-users-line { + --fa: "\e592"; + --fa--fa: "\e592\e592"; } + +.fa-quote-left { + --fa: "\f10d"; + --fa--fa: "\f10d\f10d"; } + +.fa-quote-left-alt { + --fa: "\f10d"; + --fa--fa: "\f10d\f10d"; } + +.fa-tractor { + --fa: "\f722"; + --fa--fa: "\f722\f722"; } + +.fa-trash-arrow-up { + --fa: "\f829"; + --fa--fa: "\f829\f829"; } + +.fa-trash-restore { + --fa: "\f829"; + --fa--fa: "\f829\f829"; } + +.fa-arrow-down-up-lock { + --fa: "\e4b0"; + --fa--fa: "\e4b0\e4b0"; } + +.fa-lines-leaning { + --fa: "\e51e"; + --fa--fa: "\e51e\e51e"; } + +.fa-ruler-combined { + --fa: "\f546"; + --fa--fa: "\f546\f546"; } + +.fa-copyright { + --fa: "\f1f9"; + --fa--fa: "\f1f9\f1f9"; } + +.fa-equals { + --fa: "\3d"; + --fa--fa: "\3d\3d"; } + +.fa-blender { + --fa: "\f517"; + --fa--fa: "\f517\f517"; } + +.fa-teeth { + --fa: "\f62e"; + --fa--fa: "\f62e\f62e"; } + +.fa-shekel-sign { + --fa: "\f20b"; + --fa--fa: "\f20b\f20b"; } + +.fa-ils { + --fa: "\f20b"; + --fa--fa: "\f20b\f20b"; } + +.fa-shekel { + --fa: "\f20b"; + --fa--fa: "\f20b\f20b"; } + +.fa-sheqel { + --fa: "\f20b"; + --fa--fa: "\f20b\f20b"; } + +.fa-sheqel-sign { + --fa: "\f20b"; + --fa--fa: "\f20b\f20b"; } + +.fa-map { + --fa: "\f279"; + --fa--fa: "\f279\f279"; } + +.fa-rocket { + --fa: "\f135"; + --fa--fa: "\f135\f135"; } + +.fa-photo-film { + --fa: "\f87c"; + --fa--fa: "\f87c\f87c"; } + +.fa-photo-video { + --fa: "\f87c"; + --fa--fa: "\f87c\f87c"; } + +.fa-folder-minus { + --fa: "\f65d"; + --fa--fa: "\f65d\f65d"; } + +.fa-hexagon-nodes-bolt { + --fa: "\e69a"; + --fa--fa: "\e69a\e69a"; } + +.fa-store { + --fa: "\f54e"; + --fa--fa: "\f54e\f54e"; } + +.fa-arrow-trend-up { + --fa: "\e098"; + --fa--fa: "\e098\e098"; } + +.fa-plug-circle-minus { + --fa: "\e55e"; + --fa--fa: "\e55e\e55e"; } + +.fa-sign-hanging { + --fa: "\f4d9"; + --fa--fa: "\f4d9\f4d9"; } + +.fa-sign { + --fa: "\f4d9"; + --fa--fa: "\f4d9\f4d9"; } + +.fa-bezier-curve { + --fa: "\f55b"; + --fa--fa: "\f55b\f55b"; } + +.fa-bell-slash { + --fa: "\f1f6"; + --fa--fa: "\f1f6\f1f6"; } + +.fa-tablet { + --fa: "\f3fb"; + --fa--fa: "\f3fb\f3fb"; } + +.fa-tablet-android { + --fa: "\f3fb"; + --fa--fa: "\f3fb\f3fb"; } + +.fa-school-flag { + --fa: "\e56e"; + --fa--fa: "\e56e\e56e"; } + +.fa-fill { + --fa: "\f575"; + --fa--fa: "\f575\f575"; } + +.fa-angle-up { + --fa: "\f106"; + --fa--fa: "\f106\f106"; } + +.fa-drumstick-bite { + --fa: "\f6d7"; + --fa--fa: "\f6d7\f6d7"; } + +.fa-holly-berry { + --fa: "\f7aa"; + --fa--fa: "\f7aa\f7aa"; } + +.fa-chevron-left { + --fa: "\f053"; + --fa--fa: "\f053\f053"; } + +.fa-bacteria { + --fa: "\e059"; + --fa--fa: "\e059\e059"; } + +.fa-hand-lizard { + --fa: "\f258"; + --fa--fa: "\f258\f258"; } + +.fa-notdef { + --fa: "\e1fe"; + --fa--fa: "\e1fe\e1fe"; } + +.fa-disease { + --fa: "\f7fa"; + --fa--fa: "\f7fa\f7fa"; } + +.fa-briefcase-medical { + --fa: "\f469"; + --fa--fa: "\f469\f469"; } + +.fa-genderless { + --fa: "\f22d"; + --fa--fa: "\f22d\f22d"; } + +.fa-chevron-right { + --fa: "\f054"; + --fa--fa: "\f054\f054"; } + +.fa-retweet { + --fa: "\f079"; + --fa--fa: "\f079\f079"; } + +.fa-car-rear { + --fa: "\f5de"; + --fa--fa: "\f5de\f5de"; } + +.fa-car-alt { + --fa: "\f5de"; + --fa--fa: "\f5de\f5de"; } + +.fa-pump-soap { + --fa: "\e06b"; + --fa--fa: "\e06b\e06b"; } + +.fa-video-slash { + --fa: "\f4e2"; + --fa--fa: "\f4e2\f4e2"; } + +.fa-battery-quarter { + --fa: "\f243"; + --fa--fa: "\f243\f243"; } + +.fa-battery-2 { + --fa: "\f243"; + --fa--fa: "\f243\f243"; } + +.fa-radio { + --fa: "\f8d7"; + --fa--fa: "\f8d7\f8d7"; } + +.fa-baby-carriage { + --fa: "\f77d"; + --fa--fa: "\f77d\f77d"; } + +.fa-carriage-baby { + --fa: "\f77d"; + --fa--fa: "\f77d\f77d"; } + +.fa-traffic-light { + --fa: "\f637"; + --fa--fa: "\f637\f637"; } + +.fa-thermometer { + --fa: "\f491"; + --fa--fa: "\f491\f491"; } + +.fa-vr-cardboard { + --fa: "\f729"; + --fa--fa: "\f729\f729"; } + +.fa-hand-middle-finger { + --fa: "\f806"; + --fa--fa: "\f806\f806"; } + +.fa-percent { + --fa: "\25"; + --fa--fa: "\25\25"; } + +.fa-percentage { + --fa: "\25"; + --fa--fa: "\25\25"; } + +.fa-truck-moving { + --fa: "\f4df"; + --fa--fa: "\f4df\f4df"; } + +.fa-glass-water-droplet { + --fa: "\e4f5"; + --fa--fa: "\e4f5\e4f5"; } + +.fa-display { + --fa: "\e163"; + --fa--fa: "\e163\e163"; } + +.fa-face-smile { + --fa: "\f118"; + --fa--fa: "\f118\f118"; } + +.fa-smile { + --fa: "\f118"; + --fa--fa: "\f118\f118"; } + +.fa-thumbtack { + --fa: "\f08d"; + --fa--fa: "\f08d\f08d"; } + +.fa-thumb-tack { + --fa: "\f08d"; + --fa--fa: "\f08d\f08d"; } + +.fa-trophy { + --fa: "\f091"; + --fa--fa: "\f091\f091"; } + +.fa-person-praying { + --fa: "\f683"; + --fa--fa: "\f683\f683"; } + +.fa-pray { + --fa: "\f683"; + --fa--fa: "\f683\f683"; } + +.fa-hammer { + --fa: "\f6e3"; + --fa--fa: "\f6e3\f6e3"; } + +.fa-hand-peace { + --fa: "\f25b"; + --fa--fa: "\f25b\f25b"; } + +.fa-rotate { + --fa: "\f2f1"; + --fa--fa: "\f2f1\f2f1"; } + +.fa-sync-alt { + --fa: "\f2f1"; + --fa--fa: "\f2f1\f2f1"; } + +.fa-spinner { + --fa: "\f110"; + --fa--fa: "\f110\f110"; } + +.fa-robot { + --fa: "\f544"; + --fa--fa: "\f544\f544"; } + +.fa-peace { + --fa: "\f67c"; + --fa--fa: "\f67c\f67c"; } + +.fa-gears { + --fa: "\f085"; + --fa--fa: "\f085\f085"; } + +.fa-cogs { + --fa: "\f085"; + --fa--fa: "\f085\f085"; } + +.fa-warehouse { + --fa: "\f494"; + --fa--fa: "\f494\f494"; } + +.fa-arrow-up-right-dots { + --fa: "\e4b7"; + --fa--fa: "\e4b7\e4b7"; } + +.fa-splotch { + --fa: "\f5bc"; + --fa--fa: "\f5bc\f5bc"; } + +.fa-face-grin-hearts { + --fa: "\f584"; + --fa--fa: "\f584\f584"; } + +.fa-grin-hearts { + --fa: "\f584"; + --fa--fa: "\f584\f584"; } + +.fa-dice-four { + --fa: "\f524"; + --fa--fa: "\f524\f524"; } + +.fa-sim-card { + --fa: "\f7c4"; + --fa--fa: "\f7c4\f7c4"; } + +.fa-transgender { + --fa: "\f225"; + --fa--fa: "\f225\f225"; } + +.fa-transgender-alt { + --fa: "\f225"; + --fa--fa: "\f225\f225"; } + +.fa-mercury { + --fa: "\f223"; + --fa--fa: "\f223\f223"; } + +.fa-arrow-turn-down { + --fa: "\f149"; + --fa--fa: "\f149\f149"; } + +.fa-level-down { + --fa: "\f149"; + --fa--fa: "\f149\f149"; } + +.fa-person-falling-burst { + --fa: "\e547"; + --fa--fa: "\e547\e547"; } + +.fa-award { + --fa: "\f559"; + --fa--fa: "\f559\f559"; } + +.fa-ticket-simple { + --fa: "\f3ff"; + --fa--fa: "\f3ff\f3ff"; } + +.fa-ticket-alt { + --fa: "\f3ff"; + --fa--fa: "\f3ff\f3ff"; } + +.fa-building { + --fa: "\f1ad"; + --fa--fa: "\f1ad\f1ad"; } + +.fa-angles-left { + --fa: "\f100"; + --fa--fa: "\f100\f100"; } + +.fa-angle-double-left { + --fa: "\f100"; + --fa--fa: "\f100\f100"; } + +.fa-qrcode { + --fa: "\f029"; + --fa--fa: "\f029\f029"; } + +.fa-clock-rotate-left { + --fa: "\f1da"; + --fa--fa: "\f1da\f1da"; } + +.fa-history { + --fa: "\f1da"; + --fa--fa: "\f1da\f1da"; } + +.fa-face-grin-beam-sweat { + --fa: "\f583"; + --fa--fa: "\f583\f583"; } + +.fa-grin-beam-sweat { + --fa: "\f583"; + --fa--fa: "\f583\f583"; } + +.fa-file-export { + --fa: "\f56e"; + --fa--fa: "\f56e\f56e"; } + +.fa-arrow-right-from-file { + --fa: "\f56e"; + --fa--fa: "\f56e\f56e"; } + +.fa-shield { + --fa: "\f132"; + --fa--fa: "\f132\f132"; } + +.fa-shield-blank { + --fa: "\f132"; + --fa--fa: "\f132\f132"; } + +.fa-arrow-up-short-wide { + --fa: "\f885"; + --fa--fa: "\f885\f885"; } + +.fa-sort-amount-up-alt { + --fa: "\f885"; + --fa--fa: "\f885\f885"; } + +.fa-comment-nodes { + --fa: "\e696"; + --fa--fa: "\e696\e696"; } + +.fa-house-medical { + --fa: "\e3b2"; + --fa--fa: "\e3b2\e3b2"; } + +.fa-golf-ball-tee { + --fa: "\f450"; + --fa--fa: "\f450\f450"; } + +.fa-golf-ball { + --fa: "\f450"; + --fa--fa: "\f450\f450"; } + +.fa-circle-chevron-left { + --fa: "\f137"; + --fa--fa: "\f137\f137"; } + +.fa-chevron-circle-left { + --fa: "\f137"; + --fa--fa: "\f137\f137"; } + +.fa-house-chimney-window { + --fa: "\e00d"; + --fa--fa: "\e00d\e00d"; } + +.fa-pen-nib { + --fa: "\f5ad"; + --fa--fa: "\f5ad\f5ad"; } + +.fa-tent-arrow-turn-left { + --fa: "\e580"; + --fa--fa: "\e580\e580"; } + +.fa-tents { + --fa: "\e582"; + --fa--fa: "\e582\e582"; } + +.fa-wand-magic { + --fa: "\f0d0"; + --fa--fa: "\f0d0\f0d0"; } + +.fa-magic { + --fa: "\f0d0"; + --fa--fa: "\f0d0\f0d0"; } + +.fa-dog { + --fa: "\f6d3"; + --fa--fa: "\f6d3\f6d3"; } + +.fa-carrot { + --fa: "\f787"; + --fa--fa: "\f787\f787"; } + +.fa-moon { + --fa: "\f186"; + --fa--fa: "\f186\f186"; } + +.fa-wine-glass-empty { + --fa: "\f5ce"; + --fa--fa: "\f5ce\f5ce"; } + +.fa-wine-glass-alt { + --fa: "\f5ce"; + --fa--fa: "\f5ce\f5ce"; } + +.fa-cheese { + --fa: "\f7ef"; + --fa--fa: "\f7ef\f7ef"; } + +.fa-yin-yang { + --fa: "\f6ad"; + --fa--fa: "\f6ad\f6ad"; } + +.fa-music { + --fa: "\f001"; + --fa--fa: "\f001\f001"; } + +.fa-code-commit { + --fa: "\f386"; + --fa--fa: "\f386\f386"; } + +.fa-temperature-low { + --fa: "\f76b"; + --fa--fa: "\f76b\f76b"; } + +.fa-person-biking { + --fa: "\f84a"; + --fa--fa: "\f84a\f84a"; } + +.fa-biking { + --fa: "\f84a"; + --fa--fa: "\f84a\f84a"; } + +.fa-broom { + --fa: "\f51a"; + --fa--fa: "\f51a\f51a"; } + +.fa-shield-heart { + --fa: "\e574"; + --fa--fa: "\e574\e574"; } + +.fa-gopuram { + --fa: "\f664"; + --fa--fa: "\f664\f664"; } + +.fa-earth-oceania { + --fa: "\e47b"; + --fa--fa: "\e47b\e47b"; } + +.fa-globe-oceania { + --fa: "\e47b"; + --fa--fa: "\e47b\e47b"; } + +.fa-square-xmark { + --fa: "\f2d3"; + --fa--fa: "\f2d3\f2d3"; } + +.fa-times-square { + --fa: "\f2d3"; + --fa--fa: "\f2d3\f2d3"; } + +.fa-xmark-square { + --fa: "\f2d3"; + --fa--fa: "\f2d3\f2d3"; } + +.fa-hashtag { + --fa: "\23"; + --fa--fa: "\23\23"; } + +.fa-up-right-and-down-left-from-center { + --fa: "\f424"; + --fa--fa: "\f424\f424"; } + +.fa-expand-alt { + --fa: "\f424"; + --fa--fa: "\f424\f424"; } + +.fa-oil-can { + --fa: "\f613"; + --fa--fa: "\f613\f613"; } + +.fa-t { + --fa: "\54"; + --fa--fa: "\54\54"; } + +.fa-hippo { + --fa: "\f6ed"; + --fa--fa: "\f6ed\f6ed"; } + +.fa-chart-column { + --fa: "\e0e3"; + --fa--fa: "\e0e3\e0e3"; } + +.fa-infinity { + --fa: "\f534"; + --fa--fa: "\f534\f534"; } + +.fa-vial-circle-check { + --fa: "\e596"; + --fa--fa: "\e596\e596"; } + +.fa-person-arrow-down-to-line { + --fa: "\e538"; + --fa--fa: "\e538\e538"; } + +.fa-voicemail { + --fa: "\f897"; + --fa--fa: "\f897\f897"; } + +.fa-fan { + --fa: "\f863"; + --fa--fa: "\f863\f863"; } + +.fa-person-walking-luggage { + --fa: "\e554"; + --fa--fa: "\e554\e554"; } + +.fa-up-down { + --fa: "\f338"; + --fa--fa: "\f338\f338"; } + +.fa-arrows-alt-v { + --fa: "\f338"; + --fa--fa: "\f338\f338"; } + +.fa-cloud-moon-rain { + --fa: "\f73c"; + --fa--fa: "\f73c\f73c"; } + +.fa-calendar { + --fa: "\f133"; + --fa--fa: "\f133\f133"; } + +.fa-trailer { + --fa: "\e041"; + --fa--fa: "\e041\e041"; } + +.fa-bahai { + --fa: "\f666"; + --fa--fa: "\f666\f666"; } + +.fa-haykal { + --fa: "\f666"; + --fa--fa: "\f666\f666"; } + +.fa-sd-card { + --fa: "\f7c2"; + --fa--fa: "\f7c2\f7c2"; } + +.fa-dragon { + --fa: "\f6d5"; + --fa--fa: "\f6d5\f6d5"; } + +.fa-shoe-prints { + --fa: "\f54b"; + --fa--fa: "\f54b\f54b"; } + +.fa-circle-plus { + --fa: "\f055"; + --fa--fa: "\f055\f055"; } + +.fa-plus-circle { + --fa: "\f055"; + --fa--fa: "\f055\f055"; } + +.fa-face-grin-tongue-wink { + --fa: "\f58b"; + --fa--fa: "\f58b\f58b"; } + +.fa-grin-tongue-wink { + --fa: "\f58b"; + --fa--fa: "\f58b\f58b"; } + +.fa-hand-holding { + --fa: "\f4bd"; + --fa--fa: "\f4bd\f4bd"; } + +.fa-plug-circle-exclamation { + --fa: "\e55d"; + --fa--fa: "\e55d\e55d"; } + +.fa-link-slash { + --fa: "\f127"; + --fa--fa: "\f127\f127"; } + +.fa-chain-broken { + --fa: "\f127"; + --fa--fa: "\f127\f127"; } + +.fa-chain-slash { + --fa: "\f127"; + --fa--fa: "\f127\f127"; } + +.fa-unlink { + --fa: "\f127"; + --fa--fa: "\f127\f127"; } + +.fa-clone { + --fa: "\f24d"; + --fa--fa: "\f24d\f24d"; } + +.fa-person-walking-arrow-loop-left { + --fa: "\e551"; + --fa--fa: "\e551\e551"; } + +.fa-arrow-up-z-a { + --fa: "\f882"; + --fa--fa: "\f882\f882"; } + +.fa-sort-alpha-up-alt { + --fa: "\f882"; + --fa--fa: "\f882\f882"; } + +.fa-fire-flame-curved { + --fa: "\f7e4"; + --fa--fa: "\f7e4\f7e4"; } + +.fa-fire-alt { + --fa: "\f7e4"; + --fa--fa: "\f7e4\f7e4"; } + +.fa-tornado { + --fa: "\f76f"; + --fa--fa: "\f76f\f76f"; } + +.fa-file-circle-plus { + --fa: "\e494"; + --fa--fa: "\e494\e494"; } + +.fa-book-quran { + --fa: "\f687"; + --fa--fa: "\f687\f687"; } + +.fa-quran { + --fa: "\f687"; + --fa--fa: "\f687\f687"; } + +.fa-anchor { + --fa: "\f13d"; + --fa--fa: "\f13d\f13d"; } + +.fa-border-all { + --fa: "\f84c"; + --fa--fa: "\f84c\f84c"; } + +.fa-face-angry { + --fa: "\f556"; + --fa--fa: "\f556\f556"; } + +.fa-angry { + --fa: "\f556"; + --fa--fa: "\f556\f556"; } + +.fa-cookie-bite { + --fa: "\f564"; + --fa--fa: "\f564\f564"; } + +.fa-arrow-trend-down { + --fa: "\e097"; + --fa--fa: "\e097\e097"; } + +.fa-rss { + --fa: "\f09e"; + --fa--fa: "\f09e\f09e"; } + +.fa-feed { + --fa: "\f09e"; + --fa--fa: "\f09e\f09e"; } + +.fa-draw-polygon { + --fa: "\f5ee"; + --fa--fa: "\f5ee\f5ee"; } + +.fa-scale-balanced { + --fa: "\f24e"; + --fa--fa: "\f24e\f24e"; } + +.fa-balance-scale { + --fa: "\f24e"; + --fa--fa: "\f24e\f24e"; } + +.fa-gauge-simple-high { + --fa: "\f62a"; + --fa--fa: "\f62a\f62a"; } + +.fa-tachometer { + --fa: "\f62a"; + --fa--fa: "\f62a\f62a"; } + +.fa-tachometer-fast { + --fa: "\f62a"; + --fa--fa: "\f62a\f62a"; } + +.fa-shower { + --fa: "\f2cc"; + --fa--fa: "\f2cc\f2cc"; } + +.fa-desktop { + --fa: "\f390"; + --fa--fa: "\f390\f390"; } + +.fa-desktop-alt { + --fa: "\f390"; + --fa--fa: "\f390\f390"; } + +.fa-m { + --fa: "\4d"; + --fa--fa: "\4d\4d"; } + +.fa-table-list { + --fa: "\f00b"; + --fa--fa: "\f00b\f00b"; } + +.fa-th-list { + --fa: "\f00b"; + --fa--fa: "\f00b\f00b"; } + +.fa-comment-sms { + --fa: "\f7cd"; + --fa--fa: "\f7cd\f7cd"; } + +.fa-sms { + --fa: "\f7cd"; + --fa--fa: "\f7cd\f7cd"; } + +.fa-book { + --fa: "\f02d"; + --fa--fa: "\f02d\f02d"; } + +.fa-user-plus { + --fa: "\f234"; + --fa--fa: "\f234\f234"; } + +.fa-check { + --fa: "\f00c"; + --fa--fa: "\f00c\f00c"; } + +.fa-battery-three-quarters { + --fa: "\f241"; + --fa--fa: "\f241\f241"; } + +.fa-battery-4 { + --fa: "\f241"; + --fa--fa: "\f241\f241"; } + +.fa-house-circle-check { + --fa: "\e509"; + --fa--fa: "\e509\e509"; } + +.fa-angle-left { + --fa: "\f104"; + --fa--fa: "\f104\f104"; } + +.fa-diagram-successor { + --fa: "\e47a"; + --fa--fa: "\e47a\e47a"; } + +.fa-truck-arrow-right { + --fa: "\e58b"; + --fa--fa: "\e58b\e58b"; } + +.fa-arrows-split-up-and-left { + --fa: "\e4bc"; + --fa--fa: "\e4bc\e4bc"; } + +.fa-hand-fist { + --fa: "\f6de"; + --fa--fa: "\f6de\f6de"; } + +.fa-fist-raised { + --fa: "\f6de"; + --fa--fa: "\f6de\f6de"; } + +.fa-cloud-moon { + --fa: "\f6c3"; + --fa--fa: "\f6c3\f6c3"; } + +.fa-briefcase { + --fa: "\f0b1"; + --fa--fa: "\f0b1\f0b1"; } + +.fa-person-falling { + --fa: "\e546"; + --fa--fa: "\e546\e546"; } + +.fa-image-portrait { + --fa: "\f3e0"; + --fa--fa: "\f3e0\f3e0"; } + +.fa-portrait { + --fa: "\f3e0"; + --fa--fa: "\f3e0\f3e0"; } + +.fa-user-tag { + --fa: "\f507"; + --fa--fa: "\f507\f507"; } + +.fa-rug { + --fa: "\e569"; + --fa--fa: "\e569\e569"; } + +.fa-earth-europe { + --fa: "\f7a2"; + --fa--fa: "\f7a2\f7a2"; } + +.fa-globe-europe { + --fa: "\f7a2"; + --fa--fa: "\f7a2\f7a2"; } + +.fa-cart-flatbed-suitcase { + --fa: "\f59d"; + --fa--fa: "\f59d\f59d"; } + +.fa-luggage-cart { + --fa: "\f59d"; + --fa--fa: "\f59d\f59d"; } + +.fa-rectangle-xmark { + --fa: "\f410"; + --fa--fa: "\f410\f410"; } + +.fa-rectangle-times { + --fa: "\f410"; + --fa--fa: "\f410\f410"; } + +.fa-times-rectangle { + --fa: "\f410"; + --fa--fa: "\f410\f410"; } + +.fa-window-close { + --fa: "\f410"; + --fa--fa: "\f410\f410"; } + +.fa-baht-sign { + --fa: "\e0ac"; + --fa--fa: "\e0ac\e0ac"; } + +.fa-book-open { + --fa: "\f518"; + --fa--fa: "\f518\f518"; } + +.fa-book-journal-whills { + --fa: "\f66a"; + --fa--fa: "\f66a\f66a"; } + +.fa-journal-whills { + --fa: "\f66a"; + --fa--fa: "\f66a\f66a"; } + +.fa-handcuffs { + --fa: "\e4f8"; + --fa--fa: "\e4f8\e4f8"; } + +.fa-triangle-exclamation { + --fa: "\f071"; + --fa--fa: "\f071\f071"; } + +.fa-exclamation-triangle { + --fa: "\f071"; + --fa--fa: "\f071\f071"; } + +.fa-warning { + --fa: "\f071"; + --fa--fa: "\f071\f071"; } + +.fa-database { + --fa: "\f1c0"; + --fa--fa: "\f1c0\f1c0"; } + +.fa-share { + --fa: "\f064"; + --fa--fa: "\f064\f064"; } + +.fa-mail-forward { + --fa: "\f064"; + --fa--fa: "\f064\f064"; } + +.fa-bottle-droplet { + --fa: "\e4c4"; + --fa--fa: "\e4c4\e4c4"; } + +.fa-mask-face { + --fa: "\e1d7"; + --fa--fa: "\e1d7\e1d7"; } + +.fa-hill-rockslide { + --fa: "\e508"; + --fa--fa: "\e508\e508"; } + +.fa-right-left { + --fa: "\f362"; + --fa--fa: "\f362\f362"; } + +.fa-exchange-alt { + --fa: "\f362"; + --fa--fa: "\f362\f362"; } + +.fa-paper-plane { + --fa: "\f1d8"; + --fa--fa: "\f1d8\f1d8"; } + +.fa-road-circle-exclamation { + --fa: "\e565"; + --fa--fa: "\e565\e565"; } + +.fa-dungeon { + --fa: "\f6d9"; + --fa--fa: "\f6d9\f6d9"; } + +.fa-align-right { + --fa: "\f038"; + --fa--fa: "\f038\f038"; } + +.fa-money-bill-1-wave { + --fa: "\f53b"; + --fa--fa: "\f53b\f53b"; } + +.fa-money-bill-wave-alt { + --fa: "\f53b"; + --fa--fa: "\f53b\f53b"; } + +.fa-life-ring { + --fa: "\f1cd"; + --fa--fa: "\f1cd\f1cd"; } + +.fa-hands { + --fa: "\f2a7"; + --fa--fa: "\f2a7\f2a7"; } + +.fa-sign-language { + --fa: "\f2a7"; + --fa--fa: "\f2a7\f2a7"; } + +.fa-signing { + --fa: "\f2a7"; + --fa--fa: "\f2a7\f2a7"; } + +.fa-calendar-day { + --fa: "\f783"; + --fa--fa: "\f783\f783"; } + +.fa-water-ladder { + --fa: "\f5c5"; + --fa--fa: "\f5c5\f5c5"; } + +.fa-ladder-water { + --fa: "\f5c5"; + --fa--fa: "\f5c5\f5c5"; } + +.fa-swimming-pool { + --fa: "\f5c5"; + --fa--fa: "\f5c5\f5c5"; } + +.fa-arrows-up-down { + --fa: "\f07d"; + --fa--fa: "\f07d\f07d"; } + +.fa-arrows-v { + --fa: "\f07d"; + --fa--fa: "\f07d\f07d"; } + +.fa-face-grimace { + --fa: "\f57f"; + --fa--fa: "\f57f\f57f"; } + +.fa-grimace { + --fa: "\f57f"; + --fa--fa: "\f57f\f57f"; } + +.fa-wheelchair-move { + --fa: "\e2ce"; + --fa--fa: "\e2ce\e2ce"; } + +.fa-wheelchair-alt { + --fa: "\e2ce"; + --fa--fa: "\e2ce\e2ce"; } + +.fa-turn-down { + --fa: "\f3be"; + --fa--fa: "\f3be\f3be"; } + +.fa-level-down-alt { + --fa: "\f3be"; + --fa--fa: "\f3be\f3be"; } + +.fa-person-walking-arrow-right { + --fa: "\e552"; + --fa--fa: "\e552\e552"; } + +.fa-square-envelope { + --fa: "\f199"; + --fa--fa: "\f199\f199"; } + +.fa-envelope-square { + --fa: "\f199"; + --fa--fa: "\f199\f199"; } + +.fa-dice { + --fa: "\f522"; + --fa--fa: "\f522\f522"; } + +.fa-bowling-ball { + --fa: "\f436"; + --fa--fa: "\f436\f436"; } + +.fa-brain { + --fa: "\f5dc"; + --fa--fa: "\f5dc\f5dc"; } + +.fa-bandage { + --fa: "\f462"; + --fa--fa: "\f462\f462"; } + +.fa-band-aid { + --fa: "\f462"; + --fa--fa: "\f462\f462"; } + +.fa-calendar-minus { + --fa: "\f272"; + --fa--fa: "\f272\f272"; } + +.fa-circle-xmark { + --fa: "\f057"; + --fa--fa: "\f057\f057"; } + +.fa-times-circle { + --fa: "\f057"; + --fa--fa: "\f057\f057"; } + +.fa-xmark-circle { + --fa: "\f057"; + --fa--fa: "\f057\f057"; } + +.fa-gifts { + --fa: "\f79c"; + --fa--fa: "\f79c\f79c"; } + +.fa-hotel { + --fa: "\f594"; + --fa--fa: "\f594\f594"; } + +.fa-earth-asia { + --fa: "\f57e"; + --fa--fa: "\f57e\f57e"; } + +.fa-globe-asia { + --fa: "\f57e"; + --fa--fa: "\f57e\f57e"; } + +.fa-id-card-clip { + --fa: "\f47f"; + --fa--fa: "\f47f\f47f"; } + +.fa-id-card-alt { + --fa: "\f47f"; + --fa--fa: "\f47f\f47f"; } + +.fa-magnifying-glass-plus { + --fa: "\f00e"; + --fa--fa: "\f00e\f00e"; } + +.fa-search-plus { + --fa: "\f00e"; + --fa--fa: "\f00e\f00e"; } + +.fa-thumbs-up { + --fa: "\f164"; + --fa--fa: "\f164\f164"; } + +.fa-user-clock { + --fa: "\f4fd"; + --fa--fa: "\f4fd\f4fd"; } + +.fa-hand-dots { + --fa: "\f461"; + --fa--fa: "\f461\f461"; } + +.fa-allergies { + --fa: "\f461"; + --fa--fa: "\f461\f461"; } + +.fa-file-invoice { + --fa: "\f570"; + --fa--fa: "\f570\f570"; } + +.fa-window-minimize { + --fa: "\f2d1"; + --fa--fa: "\f2d1\f2d1"; } + +.fa-mug-saucer { + --fa: "\f0f4"; + --fa--fa: "\f0f4\f0f4"; } + +.fa-coffee { + --fa: "\f0f4"; + --fa--fa: "\f0f4\f0f4"; } + +.fa-brush { + --fa: "\f55d"; + --fa--fa: "\f55d\f55d"; } + +.fa-file-half-dashed { + --fa: "\e698"; + --fa--fa: "\e698\e698"; } + +.fa-mask { + --fa: "\f6fa"; + --fa--fa: "\f6fa\f6fa"; } + +.fa-magnifying-glass-minus { + --fa: "\f010"; + --fa--fa: "\f010\f010"; } + +.fa-search-minus { + --fa: "\f010"; + --fa--fa: "\f010\f010"; } + +.fa-ruler-vertical { + --fa: "\f548"; + --fa--fa: "\f548\f548"; } + +.fa-user-large { + --fa: "\f406"; + --fa--fa: "\f406\f406"; } + +.fa-user-alt { + --fa: "\f406"; + --fa--fa: "\f406\f406"; } + +.fa-train-tram { + --fa: "\e5b4"; + --fa--fa: "\e5b4\e5b4"; } + +.fa-user-nurse { + --fa: "\f82f"; + --fa--fa: "\f82f\f82f"; } + +.fa-syringe { + --fa: "\f48e"; + --fa--fa: "\f48e\f48e"; } + +.fa-cloud-sun { + --fa: "\f6c4"; + --fa--fa: "\f6c4\f6c4"; } + +.fa-stopwatch-20 { + --fa: "\e06f"; + --fa--fa: "\e06f\e06f"; } + +.fa-square-full { + --fa: "\f45c"; + --fa--fa: "\f45c\f45c"; } + +.fa-magnet { + --fa: "\f076"; + --fa--fa: "\f076\f076"; } + +.fa-jar { + --fa: "\e516"; + --fa--fa: "\e516\e516"; } + +.fa-note-sticky { + --fa: "\f249"; + --fa--fa: "\f249\f249"; } + +.fa-sticky-note { + --fa: "\f249"; + --fa--fa: "\f249\f249"; } + +.fa-bug-slash { + --fa: "\e490"; + --fa--fa: "\e490\e490"; } + +.fa-arrow-up-from-water-pump { + --fa: "\e4b6"; + --fa--fa: "\e4b6\e4b6"; } + +.fa-bone { + --fa: "\f5d7"; + --fa--fa: "\f5d7\f5d7"; } + +.fa-table-cells-row-unlock { + --fa: "\e691"; + --fa--fa: "\e691\e691"; } + +.fa-user-injured { + --fa: "\f728"; + --fa--fa: "\f728\f728"; } + +.fa-face-sad-tear { + --fa: "\f5b4"; + --fa--fa: "\f5b4\f5b4"; } + +.fa-sad-tear { + --fa: "\f5b4"; + --fa--fa: "\f5b4\f5b4"; } + +.fa-plane { + --fa: "\f072"; + --fa--fa: "\f072\f072"; } + +.fa-tent-arrows-down { + --fa: "\e581"; + --fa--fa: "\e581\e581"; } + +.fa-exclamation { + --fa: "\21"; + --fa--fa: "\21\21"; } + +.fa-arrows-spin { + --fa: "\e4bb"; + --fa--fa: "\e4bb\e4bb"; } + +.fa-print { + --fa: "\f02f"; + --fa--fa: "\f02f\f02f"; } + +.fa-turkish-lira-sign { + --fa: "\e2bb"; + --fa--fa: "\e2bb\e2bb"; } + +.fa-try { + --fa: "\e2bb"; + --fa--fa: "\e2bb\e2bb"; } + +.fa-turkish-lira { + --fa: "\e2bb"; + --fa--fa: "\e2bb\e2bb"; } + +.fa-dollar-sign { + --fa: "\24"; + --fa--fa: "\24\24"; } + +.fa-dollar { + --fa: "\24"; + --fa--fa: "\24\24"; } + +.fa-usd { + --fa: "\24"; + --fa--fa: "\24\24"; } + +.fa-x { + --fa: "\58"; + --fa--fa: "\58\58"; } + +.fa-magnifying-glass-dollar { + --fa: "\f688"; + --fa--fa: "\f688\f688"; } + +.fa-search-dollar { + --fa: "\f688"; + --fa--fa: "\f688\f688"; } + +.fa-users-gear { + --fa: "\f509"; + --fa--fa: "\f509\f509"; } + +.fa-users-cog { + --fa: "\f509"; + --fa--fa: "\f509\f509"; } + +.fa-person-military-pointing { + --fa: "\e54a"; + --fa--fa: "\e54a\e54a"; } + +.fa-building-columns { + --fa: "\f19c"; + --fa--fa: "\f19c\f19c"; } + +.fa-bank { + --fa: "\f19c"; + --fa--fa: "\f19c\f19c"; } + +.fa-institution { + --fa: "\f19c"; + --fa--fa: "\f19c\f19c"; } + +.fa-museum { + --fa: "\f19c"; + --fa--fa: "\f19c\f19c"; } + +.fa-university { + --fa: "\f19c"; + --fa--fa: "\f19c\f19c"; } + +.fa-umbrella { + --fa: "\f0e9"; + --fa--fa: "\f0e9\f0e9"; } + +.fa-trowel { + --fa: "\e589"; + --fa--fa: "\e589\e589"; } + +.fa-d { + --fa: "\44"; + --fa--fa: "\44\44"; } + +.fa-stapler { + --fa: "\e5af"; + --fa--fa: "\e5af\e5af"; } + +.fa-masks-theater { + --fa: "\f630"; + --fa--fa: "\f630\f630"; } + +.fa-theater-masks { + --fa: "\f630"; + --fa--fa: "\f630\f630"; } + +.fa-kip-sign { + --fa: "\e1c4"; + --fa--fa: "\e1c4\e1c4"; } + +.fa-hand-point-left { + --fa: "\f0a5"; + --fa--fa: "\f0a5\f0a5"; } + +.fa-handshake-simple { + --fa: "\f4c6"; + --fa--fa: "\f4c6\f4c6"; } + +.fa-handshake-alt { + --fa: "\f4c6"; + --fa--fa: "\f4c6\f4c6"; } + +.fa-jet-fighter { + --fa: "\f0fb"; + --fa--fa: "\f0fb\f0fb"; } + +.fa-fighter-jet { + --fa: "\f0fb"; + --fa--fa: "\f0fb\f0fb"; } + +.fa-square-share-nodes { + --fa: "\f1e1"; + --fa--fa: "\f1e1\f1e1"; } + +.fa-share-alt-square { + --fa: "\f1e1"; + --fa--fa: "\f1e1\f1e1"; } + +.fa-barcode { + --fa: "\f02a"; + --fa--fa: "\f02a\f02a"; } + +.fa-plus-minus { + --fa: "\e43c"; + --fa--fa: "\e43c\e43c"; } + +.fa-video { + --fa: "\f03d"; + --fa--fa: "\f03d\f03d"; } + +.fa-video-camera { + --fa: "\f03d"; + --fa--fa: "\f03d\f03d"; } + +.fa-graduation-cap { + --fa: "\f19d"; + --fa--fa: "\f19d\f19d"; } + +.fa-mortar-board { + --fa: "\f19d"; + --fa--fa: "\f19d\f19d"; } + +.fa-hand-holding-medical { + --fa: "\e05c"; + --fa--fa: "\e05c\e05c"; } + +.fa-person-circle-check { + --fa: "\e53e"; + --fa--fa: "\e53e\e53e"; } + +.fa-turn-up { + --fa: "\f3bf"; + --fa--fa: "\f3bf\f3bf"; } + +.fa-level-up-alt { + --fa: "\f3bf"; + --fa--fa: "\f3bf\f3bf"; } + +.sr-only, +.fa-sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; } + +.sr-only-focusable:not(:focus), +.fa-sr-only-focusable:not(:focus) { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; } + +/*! + * Font Awesome Free 6.7.1 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +:root, :host { + --fa-style-family-classic: 'Font Awesome 6 Free'; + --fa-font-regular: normal 400 1em/1 'Font Awesome 6 Free'; } + +@font-face { + font-family: 'Font Awesome 6 Free'; + font-style: normal; + font-weight: 400; + font-display: block; + src: url("../fonts/fa-regular-400.woff2") format("woff2"), url("../fonts/fa-regular-400.ttf") format("truetype"); } + +.far, +.fa-regular { + font-weight: 400; } + +/*! + * Font Awesome Free 6.7.1 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +:root, :host { + --fa-style-family-classic: 'Font Awesome 6 Free'; + --fa-font-solid: normal 900 1em/1 'Font Awesome 6 Free'; } + +@font-face { + font-family: 'Font Awesome 6 Free'; + font-style: normal; + font-weight: 900; + font-display: block; + src: url("../fonts/fa-solid-900.woff2") format("woff2"), url("../fonts/fa-solid-900.ttf") format("truetype"); } + +.fas, +.fa-solid, +.content article a:where(.external-link):not(:has(img)):after { + font-weight: 900; } + +/*! + * Font Awesome Free 6.7.1 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +:root, :host { + --fa-style-family-brands: 'Font Awesome 6 Brands'; + --fa-font-brands: normal 400 1em/1 'Font Awesome 6 Brands'; } + +@font-face { + font-family: 'Font Awesome 6 Brands'; + font-style: normal; + font-weight: 400; + font-display: block; + src: url("../fonts/fa-brands-400.woff2") format("woff2"), url("../fonts/fa-brands-400.ttf") format("truetype"); } + +.fab, +.fa-brands { + font-weight: 400; } + +.fa-monero { + --fa: "\f3d0"; } + +.fa-hooli { + --fa: "\f427"; } + +.fa-yelp { + --fa: "\f1e9"; } + +.fa-cc-visa { + --fa: "\f1f0"; } + +.fa-lastfm { + --fa: "\f202"; } + +.fa-shopware { + --fa: "\f5b5"; } + +.fa-creative-commons-nc { + --fa: "\f4e8"; } + +.fa-aws { + --fa: "\f375"; } + +.fa-redhat { + --fa: "\f7bc"; } + +.fa-yoast { + --fa: "\f2b1"; } + +.fa-cloudflare { + --fa: "\e07d"; } + +.fa-ups { + --fa: "\f7e0"; } + +.fa-pixiv { + --fa: "\e640"; } + +.fa-wpexplorer { + --fa: "\f2de"; } + +.fa-dyalog { + --fa: "\f399"; } + +.fa-bity { + --fa: "\f37a"; } + +.fa-stackpath { + --fa: "\f842"; } + +.fa-buysellads { + --fa: "\f20d"; } + +.fa-first-order { + --fa: "\f2b0"; } + +.fa-modx { + --fa: "\f285"; } + +.fa-guilded { + --fa: "\e07e"; } + +.fa-vnv { + --fa: "\f40b"; } + +.fa-square-js { + --fa: "\f3b9"; } + +.fa-js-square { + --fa: "\f3b9"; } + +.fa-microsoft { + --fa: "\f3ca"; } + +.fa-qq { + --fa: "\f1d6"; } + +.fa-orcid { + --fa: "\f8d2"; } + +.fa-java { + --fa: "\f4e4"; } + +.fa-invision { + --fa: "\f7b0"; } + +.fa-creative-commons-pd-alt { + --fa: "\f4ed"; } + +.fa-centercode { + --fa: "\f380"; } + +.fa-glide-g { + --fa: "\f2a6"; } + +.fa-drupal { + --fa: "\f1a9"; } + +.fa-jxl { + --fa: "\e67b"; } + +.fa-dart-lang { + --fa: "\e693"; } + +.fa-hire-a-helper { + --fa: "\f3b0"; } + +.fa-creative-commons-by { + --fa: "\f4e7"; } + +.fa-unity { + --fa: "\e049"; } + +.fa-whmcs { + --fa: "\f40d"; } + +.fa-rocketchat { + --fa: "\f3e8"; } + +.fa-vk { + --fa: "\f189"; } + +.fa-untappd { + --fa: "\f405"; } + +.fa-mailchimp { + --fa: "\f59e"; } + +.fa-css3-alt { + --fa: "\f38b"; } + +.fa-square-reddit { + --fa: "\f1a2"; } + +.fa-reddit-square { + --fa: "\f1a2"; } + +.fa-vimeo-v { + --fa: "\f27d"; } + +.fa-contao { + --fa: "\f26d"; } + +.fa-square-font-awesome { + --fa: "\e5ad"; } + +.fa-deskpro { + --fa: "\f38f"; } + +.fa-brave { + --fa: "\e63c"; } + +.fa-sistrix { + --fa: "\f3ee"; } + +.fa-square-instagram { + --fa: "\e055"; } + +.fa-instagram-square { + --fa: "\e055"; } + +.fa-battle-net { + --fa: "\f835"; } + +.fa-the-red-yeti { + --fa: "\f69d"; } + +.fa-square-hacker-news { + --fa: "\f3af"; } + +.fa-hacker-news-square { + --fa: "\f3af"; } + +.fa-edge { + --fa: "\f282"; } + +.fa-threads { + --fa: "\e618"; } + +.fa-napster { + --fa: "\f3d2"; } + +.fa-square-snapchat { + --fa: "\f2ad"; } + +.fa-snapchat-square { + --fa: "\f2ad"; } + +.fa-google-plus-g { + --fa: "\f0d5"; } + +.fa-artstation { + --fa: "\f77a"; } + +.fa-markdown { + --fa: "\f60f"; } + +.fa-sourcetree { + --fa: "\f7d3"; } + +.fa-google-plus { + --fa: "\f2b3"; } + +.fa-diaspora { + --fa: "\f791"; } + +.fa-foursquare { + --fa: "\f180"; } + +.fa-stack-overflow { + --fa: "\f16c"; } + +.fa-github-alt { + --fa: "\f113"; } + +.fa-phoenix-squadron { + --fa: "\f511"; } + +.fa-pagelines { + --fa: "\f18c"; } + +.fa-algolia { + --fa: "\f36c"; } + +.fa-red-river { + --fa: "\f3e3"; } + +.fa-creative-commons-sa { + --fa: "\f4ef"; } + +.fa-safari { + --fa: "\f267"; } + +.fa-google { + --fa: "\f1a0"; } + +.fa-square-font-awesome-stroke { + --fa: "\f35c"; } + +.fa-font-awesome-alt { + --fa: "\f35c"; } + +.fa-atlassian { + --fa: "\f77b"; } + +.fa-linkedin-in { + --fa: "\f0e1"; } + +.fa-digital-ocean { + --fa: "\f391"; } + +.fa-nimblr { + --fa: "\f5a8"; } + +.fa-chromecast { + --fa: "\f838"; } + +.fa-evernote { + --fa: "\f839"; } + +.fa-hacker-news { + --fa: "\f1d4"; } + +.fa-creative-commons-sampling { + --fa: "\f4f0"; } + +.fa-adversal { + --fa: "\f36a"; } + +.fa-creative-commons { + --fa: "\f25e"; } + +.fa-watchman-monitoring { + --fa: "\e087"; } + +.fa-fonticons { + --fa: "\f280"; } + +.fa-weixin { + --fa: "\f1d7"; } + +.fa-shirtsinbulk { + --fa: "\f214"; } + +.fa-codepen { + --fa: "\f1cb"; } + +.fa-git-alt { + --fa: "\f841"; } + +.fa-lyft { + --fa: "\f3c3"; } + +.fa-rev { + --fa: "\f5b2"; } + +.fa-windows { + --fa: "\f17a"; } + +.fa-wizards-of-the-coast { + --fa: "\f730"; } + +.fa-square-viadeo { + --fa: "\f2aa"; } + +.fa-viadeo-square { + --fa: "\f2aa"; } + +.fa-meetup { + --fa: "\f2e0"; } + +.fa-centos { + --fa: "\f789"; } + +.fa-adn { + --fa: "\f170"; } + +.fa-cloudsmith { + --fa: "\f384"; } + +.fa-opensuse { + --fa: "\e62b"; } + +.fa-pied-piper-alt { + --fa: "\f1a8"; } + +.fa-square-dribbble { + --fa: "\f397"; } + +.fa-dribbble-square { + --fa: "\f397"; } + +.fa-codiepie { + --fa: "\f284"; } + +.fa-node { + --fa: "\f419"; } + +.fa-mix { + --fa: "\f3cb"; } + +.fa-steam { + --fa: "\f1b6"; } + +.fa-cc-apple-pay { + --fa: "\f416"; } + +.fa-scribd { + --fa: "\f28a"; } + +.fa-debian { + --fa: "\e60b"; } + +.fa-openid { + --fa: "\f19b"; } + +.fa-instalod { + --fa: "\e081"; } + +.fa-files-pinwheel { + --fa: "\e69f"; } + +.fa-expeditedssl { + --fa: "\f23e"; } + +.fa-sellcast { + --fa: "\f2da"; } + +.fa-square-twitter { + --fa: "\f081"; } + +.fa-twitter-square { + --fa: "\f081"; } + +.fa-r-project { + --fa: "\f4f7"; } + +.fa-delicious { + --fa: "\f1a5"; } + +.fa-freebsd { + --fa: "\f3a4"; } + +.fa-vuejs { + --fa: "\f41f"; } + +.fa-accusoft { + --fa: "\f369"; } + +.fa-ioxhost { + --fa: "\f208"; } + +.fa-fonticons-fi { + --fa: "\f3a2"; } + +.fa-app-store { + --fa: "\f36f"; } + +.fa-cc-mastercard { + --fa: "\f1f1"; } + +.fa-itunes-note { + --fa: "\f3b5"; } + +.fa-golang { + --fa: "\e40f"; } + +.fa-kickstarter { + --fa: "\f3bb"; } + +.fa-square-kickstarter { + --fa: "\f3bb"; } + +.fa-grav { + --fa: "\f2d6"; } + +.fa-weibo { + --fa: "\f18a"; } + +.fa-uncharted { + --fa: "\e084"; } + +.fa-firstdraft { + --fa: "\f3a1"; } + +.fa-square-youtube { + --fa: "\f431"; } + +.fa-youtube-square { + --fa: "\f431"; } + +.fa-wikipedia-w { + --fa: "\f266"; } + +.fa-wpressr { + --fa: "\f3e4"; } + +.fa-rendact { + --fa: "\f3e4"; } + +.fa-angellist { + --fa: "\f209"; } + +.fa-galactic-republic { + --fa: "\f50c"; } + +.fa-nfc-directional { + --fa: "\e530"; } + +.fa-skype { + --fa: "\f17e"; } + +.fa-joget { + --fa: "\f3b7"; } + +.fa-fedora { + --fa: "\f798"; } + +.fa-stripe-s { + --fa: "\f42a"; } + +.fa-meta { + --fa: "\e49b"; } + +.fa-laravel { + --fa: "\f3bd"; } + +.fa-hotjar { + --fa: "\f3b1"; } + +.fa-bluetooth-b { + --fa: "\f294"; } + +.fa-square-letterboxd { + --fa: "\e62e"; } + +.fa-sticker-mule { + --fa: "\f3f7"; } + +.fa-creative-commons-zero { + --fa: "\f4f3"; } + +.fa-hips { + --fa: "\f452"; } + +.fa-css { + --fa: "\e6a2"; } + +.fa-behance { + --fa: "\f1b4"; } + +.fa-reddit { + --fa: "\f1a1"; } + +.fa-discord { + --fa: "\f392"; } + +.fa-chrome { + --fa: "\f268"; } + +.fa-app-store-ios { + --fa: "\f370"; } + +.fa-cc-discover { + --fa: "\f1f2"; } + +.fa-wpbeginner { + --fa: "\f297"; } + +.fa-confluence { + --fa: "\f78d"; } + +.fa-shoelace { + --fa: "\e60c"; } + +.fa-mdb { + --fa: "\f8ca"; } + +.fa-dochub { + --fa: "\f394"; } + +.fa-accessible-icon { + --fa: "\f368"; } + +.fa-ebay { + --fa: "\f4f4"; } + +.fa-amazon { + --fa: "\f270"; } + +.fa-unsplash { + --fa: "\e07c"; } + +.fa-yarn { + --fa: "\f7e3"; } + +.fa-square-steam { + --fa: "\f1b7"; } + +.fa-steam-square { + --fa: "\f1b7"; } + +.fa-500px { + --fa: "\f26e"; } + +.fa-square-vimeo { + --fa: "\f194"; } + +.fa-vimeo-square { + --fa: "\f194"; } + +.fa-asymmetrik { + --fa: "\f372"; } + +.fa-font-awesome { + --fa: "\f2b4"; } + +.fa-font-awesome-flag { + --fa: "\f2b4"; } + +.fa-font-awesome-logo-full { + --fa: "\f2b4"; } + +.fa-gratipay { + --fa: "\f184"; } + +.fa-apple { + --fa: "\f179"; } + +.fa-hive { + --fa: "\e07f"; } + +.fa-gitkraken { + --fa: "\f3a6"; } + +.fa-keybase { + --fa: "\f4f5"; } + +.fa-apple-pay { + --fa: "\f415"; } + +.fa-padlet { + --fa: "\e4a0"; } + +.fa-amazon-pay { + --fa: "\f42c"; } + +.fa-square-github { + --fa: "\f092"; } + +.fa-github-square { + --fa: "\f092"; } + +.fa-stumbleupon { + --fa: "\f1a4"; } + +.fa-fedex { + --fa: "\f797"; } + +.fa-phoenix-framework { + --fa: "\f3dc"; } + +.fa-shopify { + --fa: "\e057"; } + +.fa-neos { + --fa: "\f612"; } + +.fa-square-threads { + --fa: "\e619"; } + +.fa-hackerrank { + --fa: "\f5f7"; } + +.fa-researchgate { + --fa: "\f4f8"; } + +.fa-swift { + --fa: "\f8e1"; } + +.fa-angular { + --fa: "\f420"; } + +.fa-speakap { + --fa: "\f3f3"; } + +.fa-angrycreative { + --fa: "\f36e"; } + +.fa-y-combinator { + --fa: "\f23b"; } + +.fa-empire { + --fa: "\f1d1"; } + +.fa-envira { + --fa: "\f299"; } + +.fa-google-scholar { + --fa: "\e63b"; } + +.fa-square-gitlab { + --fa: "\e5ae"; } + +.fa-gitlab-square { + --fa: "\e5ae"; } + +.fa-studiovinari { + --fa: "\f3f8"; } + +.fa-pied-piper { + --fa: "\f2ae"; } + +.fa-wordpress { + --fa: "\f19a"; } + +.fa-product-hunt { + --fa: "\f288"; } + +.fa-firefox { + --fa: "\f269"; } + +.fa-linode { + --fa: "\f2b8"; } + +.fa-goodreads { + --fa: "\f3a8"; } + +.fa-square-odnoklassniki { + --fa: "\f264"; } + +.fa-odnoklassniki-square { + --fa: "\f264"; } + +.fa-jsfiddle { + --fa: "\f1cc"; } + +.fa-sith { + --fa: "\f512"; } + +.fa-themeisle { + --fa: "\f2b2"; } + +.fa-page4 { + --fa: "\f3d7"; } + +.fa-hashnode { + --fa: "\e499"; } + +.fa-react { + --fa: "\f41b"; } + +.fa-cc-paypal { + --fa: "\f1f4"; } + +.fa-squarespace { + --fa: "\f5be"; } + +.fa-cc-stripe { + --fa: "\f1f5"; } + +.fa-creative-commons-share { + --fa: "\f4f2"; } + +.fa-bitcoin { + --fa: "\f379"; } + +.fa-keycdn { + --fa: "\f3ba"; } + +.fa-opera { + --fa: "\f26a"; } + +.fa-itch-io { + --fa: "\f83a"; } + +.fa-umbraco { + --fa: "\f8e8"; } + +.fa-galactic-senate { + --fa: "\f50d"; } + +.fa-ubuntu { + --fa: "\f7df"; } + +.fa-draft2digital { + --fa: "\f396"; } + +.fa-stripe { + --fa: "\f429"; } + +.fa-houzz { + --fa: "\f27c"; } + +.fa-gg { + --fa: "\f260"; } + +.fa-dhl { + --fa: "\f790"; } + +.fa-square-pinterest { + --fa: "\f0d3"; } + +.fa-pinterest-square { + --fa: "\f0d3"; } + +.fa-xing { + --fa: "\f168"; } + +.fa-blackberry { + --fa: "\f37b"; } + +.fa-creative-commons-pd { + --fa: "\f4ec"; } + +.fa-playstation { + --fa: "\f3df"; } + +.fa-quinscape { + --fa: "\f459"; } + +.fa-less { + --fa: "\f41d"; } + +.fa-blogger-b { + --fa: "\f37d"; } + +.fa-opencart { + --fa: "\f23d"; } + +.fa-vine { + --fa: "\f1ca"; } + +.fa-signal-messenger { + --fa: "\e663"; } + +.fa-paypal { + --fa: "\f1ed"; } + +.fa-gitlab { + --fa: "\f296"; } + +.fa-typo3 { + --fa: "\f42b"; } + +.fa-reddit-alien { + --fa: "\f281"; } + +.fa-yahoo { + --fa: "\f19e"; } + +.fa-dailymotion { + --fa: "\e052"; } + +.fa-affiliatetheme { + --fa: "\f36b"; } + +.fa-pied-piper-pp { + --fa: "\f1a7"; } + +.fa-bootstrap { + --fa: "\f836"; } + +.fa-odnoklassniki { + --fa: "\f263"; } + +.fa-nfc-symbol { + --fa: "\e531"; } + +.fa-mintbit { + --fa: "\e62f"; } + +.fa-ethereum { + --fa: "\f42e"; } + +.fa-speaker-deck { + --fa: "\f83c"; } + +.fa-creative-commons-nc-eu { + --fa: "\f4e9"; } + +.fa-patreon { + --fa: "\f3d9"; } + +.fa-avianex { + --fa: "\f374"; } + +.fa-ello { + --fa: "\f5f1"; } + +.fa-gofore { + --fa: "\f3a7"; } + +.fa-bimobject { + --fa: "\f378"; } + +.fa-brave-reverse { + --fa: "\e63d"; } + +.fa-facebook-f { + --fa: "\f39e"; } + +.fa-square-google-plus { + --fa: "\f0d4"; } + +.fa-google-plus-square { + --fa: "\f0d4"; } + +.fa-web-awesome { + --fa: "\e682"; } + +.fa-mandalorian { + --fa: "\f50f"; } + +.fa-first-order-alt { + --fa: "\f50a"; } + +.fa-osi { + --fa: "\f41a"; } + +.fa-google-wallet { + --fa: "\f1ee"; } + +.fa-d-and-d-beyond { + --fa: "\f6ca"; } + +.fa-periscope { + --fa: "\f3da"; } + +.fa-fulcrum { + --fa: "\f50b"; } + +.fa-cloudscale { + --fa: "\f383"; } + +.fa-forumbee { + --fa: "\f211"; } + +.fa-mizuni { + --fa: "\f3cc"; } + +.fa-schlix { + --fa: "\f3ea"; } + +.fa-square-xing { + --fa: "\f169"; } + +.fa-xing-square { + --fa: "\f169"; } + +.fa-bandcamp { + --fa: "\f2d5"; } + +.fa-wpforms { + --fa: "\f298"; } + +.fa-cloudversify { + --fa: "\f385"; } + +.fa-usps { + --fa: "\f7e1"; } + +.fa-megaport { + --fa: "\f5a3"; } + +.fa-magento { + --fa: "\f3c4"; } + +.fa-spotify { + --fa: "\f1bc"; } + +.fa-optin-monster { + --fa: "\f23c"; } + +.fa-fly { + --fa: "\f417"; } + +.fa-square-bluesky { + --fa: "\e6a3"; } + +.fa-aviato { + --fa: "\f421"; } + +.fa-itunes { + --fa: "\f3b4"; } + +.fa-cuttlefish { + --fa: "\f38c"; } + +.fa-blogger { + --fa: "\f37c"; } + +.fa-flickr { + --fa: "\f16e"; } + +.fa-viber { + --fa: "\f409"; } + +.fa-soundcloud { + --fa: "\f1be"; } + +.fa-digg { + --fa: "\f1a6"; } + +.fa-tencent-weibo { + --fa: "\f1d5"; } + +.fa-letterboxd { + --fa: "\e62d"; } + +.fa-symfony { + --fa: "\f83d"; } + +.fa-maxcdn { + --fa: "\f136"; } + +.fa-etsy { + --fa: "\f2d7"; } + +.fa-facebook-messenger { + --fa: "\f39f"; } + +.fa-audible { + --fa: "\f373"; } + +.fa-think-peaks { + --fa: "\f731"; } + +.fa-bilibili { + --fa: "\e3d9"; } + +.fa-erlang { + --fa: "\f39d"; } + +.fa-x-twitter { + --fa: "\e61b"; } + +.fa-cotton-bureau { + --fa: "\f89e"; } + +.fa-dashcube { + --fa: "\f210"; } + +.fa-42-group { + --fa: "\e080"; } + +.fa-innosoft { + --fa: "\e080"; } + +.fa-stack-exchange { + --fa: "\f18d"; } + +.fa-elementor { + --fa: "\f430"; } + +.fa-square-pied-piper { + --fa: "\e01e"; } + +.fa-pied-piper-square { + --fa: "\e01e"; } + +.fa-creative-commons-nd { + --fa: "\f4eb"; } + +.fa-palfed { + --fa: "\f3d8"; } + +.fa-superpowers { + --fa: "\f2dd"; } + +.fa-resolving { + --fa: "\f3e7"; } + +.fa-xbox { + --fa: "\f412"; } + +.fa-square-web-awesome-stroke { + --fa: "\e684"; } + +.fa-searchengin { + --fa: "\f3eb"; } + +.fa-tiktok { + --fa: "\e07b"; } + +.fa-square-facebook { + --fa: "\f082"; } + +.fa-facebook-square { + --fa: "\f082"; } + +.fa-renren { + --fa: "\f18b"; } + +.fa-linux { + --fa: "\f17c"; } + +.fa-glide { + --fa: "\f2a5"; } + +.fa-linkedin { + --fa: "\f08c"; } + +.fa-hubspot { + --fa: "\f3b2"; } + +.fa-deploydog { + --fa: "\f38e"; } + +.fa-twitch { + --fa: "\f1e8"; } + +.fa-flutter { + --fa: "\e694"; } + +.fa-ravelry { + --fa: "\f2d9"; } + +.fa-mixer { + --fa: "\e056"; } + +.fa-square-lastfm { + --fa: "\f203"; } + +.fa-lastfm-square { + --fa: "\f203"; } + +.fa-vimeo { + --fa: "\f40a"; } + +.fa-mendeley { + --fa: "\f7b3"; } + +.fa-uniregistry { + --fa: "\f404"; } + +.fa-figma { + --fa: "\f799"; } + +.fa-creative-commons-remix { + --fa: "\f4ee"; } + +.fa-cc-amazon-pay { + --fa: "\f42d"; } + +.fa-dropbox { + --fa: "\f16b"; } + +.fa-instagram { + --fa: "\f16d"; } + +.fa-cmplid { + --fa: "\e360"; } + +.fa-upwork { + --fa: "\e641"; } + +.fa-facebook { + --fa: "\f09a"; } + +.fa-gripfire { + --fa: "\f3ac"; } + +.fa-jedi-order { + --fa: "\f50e"; } + +.fa-uikit { + --fa: "\f403"; } + +.fa-fort-awesome-alt { + --fa: "\f3a3"; } + +.fa-phabricator { + --fa: "\f3db"; } + +.fa-ussunnah { + --fa: "\f407"; } + +.fa-earlybirds { + --fa: "\f39a"; } + +.fa-trade-federation { + --fa: "\f513"; } + +.fa-autoprefixer { + --fa: "\f41c"; } + +.fa-whatsapp { + --fa: "\f232"; } + +.fa-square-upwork { + --fa: "\e67c"; } + +.fa-slideshare { + --fa: "\f1e7"; } + +.fa-google-play { + --fa: "\f3ab"; } + +.fa-viadeo { + --fa: "\f2a9"; } + +.fa-line { + --fa: "\f3c0"; } + +.fa-google-drive { + --fa: "\f3aa"; } + +.fa-servicestack { + --fa: "\f3ec"; } + +.fa-simplybuilt { + --fa: "\f215"; } + +.fa-bitbucket { + --fa: "\f171"; } + +.fa-imdb { + --fa: "\f2d8"; } + +.fa-deezer { + --fa: "\e077"; } + +.fa-raspberry-pi { + --fa: "\f7bb"; } + +.fa-jira { + --fa: "\f7b1"; } + +.fa-docker { + --fa: "\f395"; } + +.fa-screenpal { + --fa: "\e570"; } + +.fa-bluetooth { + --fa: "\f293"; } + +.fa-gitter { + --fa: "\f426"; } + +.fa-d-and-d { + --fa: "\f38d"; } + +.fa-microblog { + --fa: "\e01a"; } + +.fa-cc-diners-club { + --fa: "\f24c"; } + +.fa-gg-circle { + --fa: "\f261"; } + +.fa-pied-piper-hat { + --fa: "\f4e5"; } + +.fa-kickstarter-k { + --fa: "\f3bc"; } + +.fa-yandex { + --fa: "\f413"; } + +.fa-readme { + --fa: "\f4d5"; } + +.fa-html5 { + --fa: "\f13b"; } + +.fa-sellsy { + --fa: "\f213"; } + +.fa-square-web-awesome { + --fa: "\e683"; } + +.fa-sass { + --fa: "\f41e"; } + +.fa-wirsindhandwerk { + --fa: "\e2d0"; } + +.fa-wsh { + --fa: "\e2d0"; } + +.fa-buromobelexperte { + --fa: "\f37f"; } + +.fa-salesforce { + --fa: "\f83b"; } + +.fa-octopus-deploy { + --fa: "\e082"; } + +.fa-medapps { + --fa: "\f3c6"; } + +.fa-ns8 { + --fa: "\f3d5"; } + +.fa-pinterest-p { + --fa: "\f231"; } + +.fa-apper { + --fa: "\f371"; } + +.fa-fort-awesome { + --fa: "\f286"; } + +.fa-waze { + --fa: "\f83f"; } + +.fa-bluesky { + --fa: "\e671"; } + +.fa-cc-jcb { + --fa: "\f24b"; } + +.fa-snapchat { + --fa: "\f2ab"; } + +.fa-snapchat-ghost { + --fa: "\f2ab"; } + +.fa-fantasy-flight-games { + --fa: "\f6dc"; } + +.fa-rust { + --fa: "\e07a"; } + +.fa-wix { + --fa: "\f5cf"; } + +.fa-square-behance { + --fa: "\f1b5"; } + +.fa-behance-square { + --fa: "\f1b5"; } + +.fa-supple { + --fa: "\f3f9"; } + +.fa-webflow { + --fa: "\e65c"; } + +.fa-rebel { + --fa: "\f1d0"; } + +.fa-css3 { + --fa: "\f13c"; } + +.fa-staylinked { + --fa: "\f3f5"; } + +.fa-kaggle { + --fa: "\f5fa"; } + +.fa-space-awesome { + --fa: "\e5ac"; } + +.fa-deviantart { + --fa: "\f1bd"; } + +.fa-cpanel { + --fa: "\f388"; } + +.fa-goodreads-g { + --fa: "\f3a9"; } + +.fa-square-git { + --fa: "\f1d2"; } + +.fa-git-square { + --fa: "\f1d2"; } + +.fa-square-tumblr { + --fa: "\f174"; } + +.fa-tumblr-square { + --fa: "\f174"; } + +.fa-trello { + --fa: "\f181"; } + +.fa-creative-commons-nc-jp { + --fa: "\f4ea"; } + +.fa-get-pocket { + --fa: "\f265"; } + +.fa-perbyte { + --fa: "\e083"; } + +.fa-grunt { + --fa: "\f3ad"; } + +.fa-weebly { + --fa: "\f5cc"; } + +.fa-connectdevelop { + --fa: "\f20e"; } + +.fa-leanpub { + --fa: "\f212"; } + +.fa-black-tie { + --fa: "\f27e"; } + +.fa-themeco { + --fa: "\f5c6"; } + +.fa-python { + --fa: "\f3e2"; } + +.fa-android { + --fa: "\f17b"; } + +.fa-bots { + --fa: "\e340"; } + +.fa-free-code-camp { + --fa: "\f2c5"; } + +.fa-hornbill { + --fa: "\f592"; } + +.fa-js { + --fa: "\f3b8"; } + +.fa-ideal { + --fa: "\e013"; } + +.fa-git { + --fa: "\f1d3"; } + +.fa-dev { + --fa: "\f6cc"; } + +.fa-sketch { + --fa: "\f7c6"; } + +.fa-yandex-international { + --fa: "\f414"; } + +.fa-cc-amex { + --fa: "\f1f3"; } + +.fa-uber { + --fa: "\f402"; } + +.fa-github { + --fa: "\f09b"; } + +.fa-php { + --fa: "\f457"; } + +.fa-alipay { + --fa: "\f642"; } + +.fa-youtube { + --fa: "\f167"; } + +.fa-skyatlas { + --fa: "\f216"; } + +.fa-firefox-browser { + --fa: "\e007"; } + +.fa-replyd { + --fa: "\f3e6"; } + +.fa-suse { + --fa: "\f7d6"; } + +.fa-jenkins { + --fa: "\f3b6"; } + +.fa-twitter { + --fa: "\f099"; } + +.fa-rockrms { + --fa: "\f3e9"; } + +.fa-pinterest { + --fa: "\f0d2"; } + +.fa-buffer { + --fa: "\f837"; } + +.fa-npm { + --fa: "\f3d4"; } + +.fa-yammer { + --fa: "\f840"; } + +.fa-btc { + --fa: "\f15a"; } + +.fa-dribbble { + --fa: "\f17d"; } + +.fa-stumbleupon-circle { + --fa: "\f1a3"; } + +.fa-internet-explorer { + --fa: "\f26b"; } + +.fa-stubber { + --fa: "\e5c7"; } + +.fa-telegram { + --fa: "\f2c6"; } + +.fa-telegram-plane { + --fa: "\f2c6"; } + +.fa-old-republic { + --fa: "\f510"; } + +.fa-odysee { + --fa: "\e5c6"; } + +.fa-square-whatsapp { + --fa: "\f40c"; } + +.fa-whatsapp-square { + --fa: "\f40c"; } + +.fa-node-js { + --fa: "\f3d3"; } + +.fa-edge-legacy { + --fa: "\e078"; } + +.fa-slack { + --fa: "\f198"; } + +.fa-slack-hash { + --fa: "\f198"; } + +.fa-medrt { + --fa: "\f3c8"; } + +.fa-usb { + --fa: "\f287"; } + +.fa-tumblr { + --fa: "\f173"; } + +.fa-vaadin { + --fa: "\f408"; } + +.fa-quora { + --fa: "\f2c4"; } + +.fa-square-x-twitter { + --fa: "\e61a"; } + +.fa-reacteurope { + --fa: "\f75d"; } + +.fa-medium { + --fa: "\f23a"; } + +.fa-medium-m { + --fa: "\f23a"; } + +.fa-amilia { + --fa: "\f36d"; } + +.fa-mixcloud { + --fa: "\f289"; } + +.fa-flipboard { + --fa: "\f44d"; } + +.fa-viacoin { + --fa: "\f237"; } + +.fa-critical-role { + --fa: "\f6c9"; } + +.fa-sitrox { + --fa: "\e44a"; } + +.fa-discourse { + --fa: "\f393"; } + +.fa-joomla { + --fa: "\f1aa"; } + +.fa-mastodon { + --fa: "\f4f6"; } + +.fa-airbnb { + --fa: "\f834"; } + +.fa-wolf-pack-battalion { + --fa: "\f514"; } + +.fa-buy-n-large { + --fa: "\f8a6"; } + +.fa-gulp { + --fa: "\f3ae"; } + +.fa-creative-commons-sampling-plus { + --fa: "\f4f1"; } + +.fa-strava { + --fa: "\f428"; } + +.fa-ember { + --fa: "\f423"; } + +.fa-canadian-maple-leaf { + --fa: "\f785"; } + +.fa-teamspeak { + --fa: "\f4f9"; } + +.fa-pushed { + --fa: "\f3e1"; } + +.fa-wordpress-simple { + --fa: "\f411"; } + +.fa-nutritionix { + --fa: "\f3d6"; } + +.fa-wodu { + --fa: "\e088"; } + +.fa-google-pay { + --fa: "\e079"; } + +.fa-intercom { + --fa: "\f7af"; } + +.fa-zhihu { + --fa: "\f63f"; } + +.fa-korvue { + --fa: "\f42f"; } + +.fa-pix { + --fa: "\e43a"; } + +.fa-steam-symbol { + --fa: "\f3f6"; } + +/*! + * Font Awesome Free 6.7.1 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +.fa.fa-glass { + --fa: "\f000"; } + +.fa.fa-envelope-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-envelope-o { + --fa: "\f0e0"; } + +.fa.fa-star-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-star-o { + --fa: "\f005"; } + +.fa.fa-remove { + --fa: "\f00d"; } + +.fa.fa-close { + --fa: "\f00d"; } + +.fa.fa-gear { + --fa: "\f013"; } + +.fa.fa-trash-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-trash-o { + --fa: "\f2ed"; } + +.fa.fa-home { + --fa: "\f015"; } + +.fa.fa-file-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-o { + --fa: "\f15b"; } + +.fa.fa-clock-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-clock-o { + --fa: "\f017"; } + +.fa.fa-arrow-circle-o-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-down { + --fa: "\f358"; } + +.fa.fa-arrow-circle-o-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-up { + --fa: "\f35b"; } + +.fa.fa-play-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-play-circle-o { + --fa: "\f144"; } + +.fa.fa-repeat { + --fa: "\f01e"; } + +.fa.fa-rotate-right { + --fa: "\f01e"; } + +.fa.fa-refresh { + --fa: "\f021"; } + +.fa.fa-list-alt { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-list-alt { + --fa: "\f022"; } + +.fa.fa-dedent { + --fa: "\f03b"; } + +.fa.fa-video-camera { + --fa: "\f03d"; } + +.fa.fa-picture-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-picture-o { + --fa: "\f03e"; } + +.fa.fa-photo { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-photo { + --fa: "\f03e"; } + +.fa.fa-image { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-image { + --fa: "\f03e"; } + +.fa.fa-map-marker { + --fa: "\f3c5"; } + +.fa.fa-pencil-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-pencil-square-o { + --fa: "\f044"; } + +.fa.fa-edit { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-edit { + --fa: "\f044"; } + +.fa.fa-share-square-o { + --fa: "\f14d"; } + +.fa.fa-check-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-check-square-o { + --fa: "\f14a"; } + +.fa.fa-arrows { + --fa: "\f0b2"; } + +.fa.fa-times-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-times-circle-o { + --fa: "\f057"; } + +.fa.fa-check-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-check-circle-o { + --fa: "\f058"; } + +.fa.fa-mail-forward { + --fa: "\f064"; } + +.fa.fa-expand { + --fa: "\f424"; } + +.fa.fa-compress { + --fa: "\f422"; } + +.fa.fa-eye { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-eye-slash { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-warning { + --fa: "\f071"; } + +.fa.fa-calendar { + --fa: "\f073"; } + +.fa.fa-arrows-v { + --fa: "\f338"; } + +.fa.fa-arrows-h { + --fa: "\f337"; } + +.fa.fa-bar-chart { + --fa: "\e0e3"; } + +.fa.fa-bar-chart-o { + --fa: "\e0e3"; } + +.fa.fa-twitter-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-twitter-square { + --fa: "\f081"; } + +.fa.fa-facebook-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-facebook-square { + --fa: "\f082"; } + +.fa.fa-gears { + --fa: "\f085"; } + +.fa.fa-thumbs-o-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-thumbs-o-up { + --fa: "\f164"; } + +.fa.fa-thumbs-o-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-thumbs-o-down { + --fa: "\f165"; } + +.fa.fa-heart-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-heart-o { + --fa: "\f004"; } + +.fa.fa-sign-out { + --fa: "\f2f5"; } + +.fa.fa-linkedin-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-linkedin-square { + --fa: "\f08c"; } + +.fa.fa-thumb-tack { + --fa: "\f08d"; } + +.fa.fa-external-link { + --fa: "\f35d"; } + +.fa.fa-sign-in { + --fa: "\f2f6"; } + +.fa.fa-github-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-github-square { + --fa: "\f092"; } + +.fa.fa-lemon-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-lemon-o { + --fa: "\f094"; } + +.fa.fa-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-square-o { + --fa: "\f0c8"; } + +.fa.fa-bookmark-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-bookmark-o { + --fa: "\f02e"; } + +.fa.fa-twitter { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-facebook { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-facebook { + --fa: "\f39e"; } + +.fa.fa-facebook-f { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-facebook-f { + --fa: "\f39e"; } + +.fa.fa-github { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-credit-card { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-feed { + --fa: "\f09e"; } + +.fa.fa-hdd-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hdd-o { + --fa: "\f0a0"; } + +.fa.fa-hand-o-right { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-o-right { + --fa: "\f0a4"; } + +.fa.fa-hand-o-left { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-o-left { + --fa: "\f0a5"; } + +.fa.fa-hand-o-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-o-up { + --fa: "\f0a6"; } + +.fa.fa-hand-o-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-o-down { + --fa: "\f0a7"; } + +.fa.fa-globe { + --fa: "\f57d"; } + +.fa.fa-tasks { + --fa: "\f828"; } + +.fa.fa-arrows-alt { + --fa: "\f31e"; } + +.fa.fa-group { + --fa: "\f0c0"; } + +.fa.fa-chain { + --fa: "\f0c1"; } + +.fa.fa-cut { + --fa: "\f0c4"; } + +.fa.fa-files-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-files-o { + --fa: "\f0c5"; } + +.fa.fa-floppy-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-floppy-o { + --fa: "\f0c7"; } + +.fa.fa-save { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-save { + --fa: "\f0c7"; } + +.fa.fa-navicon { + --fa: "\f0c9"; } + +.fa.fa-reorder { + --fa: "\f0c9"; } + +.fa.fa-magic { + --fa: "\e2ca"; } + +.fa.fa-pinterest { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pinterest-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pinterest-square { + --fa: "\f0d3"; } + +.fa.fa-google-plus-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-plus-square { + --fa: "\f0d4"; } + +.fa.fa-google-plus { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-plus { + --fa: "\f0d5"; } + +.fa.fa-money { + --fa: "\f3d1"; } + +.fa.fa-unsorted { + --fa: "\f0dc"; } + +.fa.fa-sort-desc { + --fa: "\f0dd"; } + +.fa.fa-sort-asc { + --fa: "\f0de"; } + +.fa.fa-linkedin { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-linkedin { + --fa: "\f0e1"; } + +.fa.fa-rotate-left { + --fa: "\f0e2"; } + +.fa.fa-legal { + --fa: "\f0e3"; } + +.fa.fa-tachometer { + --fa: "\f625"; } + +.fa.fa-dashboard { + --fa: "\f625"; } + +.fa.fa-comment-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-comment-o { + --fa: "\f075"; } + +.fa.fa-comments-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-comments-o { + --fa: "\f086"; } + +.fa.fa-flash { + --fa: "\f0e7"; } + +.fa.fa-clipboard { + --fa: "\f0ea"; } + +.fa.fa-lightbulb-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-lightbulb-o { + --fa: "\f0eb"; } + +.fa.fa-exchange { + --fa: "\f362"; } + +.fa.fa-cloud-download { + --fa: "\f0ed"; } + +.fa.fa-cloud-upload { + --fa: "\f0ee"; } + +.fa.fa-bell-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-bell-o { + --fa: "\f0f3"; } + +.fa.fa-cutlery { + --fa: "\f2e7"; } + +.fa.fa-file-text-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-text-o { + --fa: "\f15c"; } + +.fa.fa-building-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-building-o { + --fa: "\f1ad"; } + +.fa.fa-hospital-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hospital-o { + --fa: "\f0f8"; } + +.fa.fa-tablet { + --fa: "\f3fa"; } + +.fa.fa-mobile { + --fa: "\f3cd"; } + +.fa.fa-mobile-phone { + --fa: "\f3cd"; } + +.fa.fa-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-circle-o { + --fa: "\f111"; } + +.fa.fa-mail-reply { + --fa: "\f3e5"; } + +.fa.fa-github-alt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-folder-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-folder-o { + --fa: "\f07b"; } + +.fa.fa-folder-open-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-folder-open-o { + --fa: "\f07c"; } + +.fa.fa-smile-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-smile-o { + --fa: "\f118"; } + +.fa.fa-frown-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-frown-o { + --fa: "\f119"; } + +.fa.fa-meh-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-meh-o { + --fa: "\f11a"; } + +.fa.fa-keyboard-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-keyboard-o { + --fa: "\f11c"; } + +.fa.fa-flag-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-flag-o { + --fa: "\f024"; } + +.fa.fa-mail-reply-all { + --fa: "\f122"; } + +.fa.fa-star-half-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-star-half-o { + --fa: "\f5c0"; } + +.fa.fa-star-half-empty { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-star-half-empty { + --fa: "\f5c0"; } + +.fa.fa-star-half-full { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-star-half-full { + --fa: "\f5c0"; } + +.fa.fa-code-fork { + --fa: "\f126"; } + +.fa.fa-chain-broken { + --fa: "\f127"; } + +.fa.fa-unlink { + --fa: "\f127"; } + +.fa.fa-calendar-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-calendar-o { + --fa: "\f133"; } + +.fa.fa-maxcdn { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-html5 { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-css3 { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-unlock-alt { + --fa: "\f09c"; } + +.fa.fa-minus-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-minus-square-o { + --fa: "\f146"; } + +.fa.fa-level-up { + --fa: "\f3bf"; } + +.fa.fa-level-down { + --fa: "\f3be"; } + +.fa.fa-pencil-square { + --fa: "\f14b"; } + +.fa.fa-external-link-square { + --fa: "\f360"; } + +.fa.fa-compass { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-down { + --fa: "\f150"; } + +.fa.fa-toggle-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-toggle-down { + --fa: "\f150"; } + +.fa.fa-caret-square-o-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-up { + --fa: "\f151"; } + +.fa.fa-toggle-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-toggle-up { + --fa: "\f151"; } + +.fa.fa-caret-square-o-right { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-right { + --fa: "\f152"; } + +.fa.fa-toggle-right { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-toggle-right { + --fa: "\f152"; } + +.fa.fa-eur { + --fa: "\f153"; } + +.fa.fa-euro { + --fa: "\f153"; } + +.fa.fa-gbp { + --fa: "\f154"; } + +.fa.fa-usd { + --fa: "\24"; } + +.fa.fa-dollar { + --fa: "\24"; } + +.fa.fa-inr { + --fa: "\e1bc"; } + +.fa.fa-rupee { + --fa: "\e1bc"; } + +.fa.fa-jpy { + --fa: "\f157"; } + +.fa.fa-cny { + --fa: "\f157"; } + +.fa.fa-rmb { + --fa: "\f157"; } + +.fa.fa-yen { + --fa: "\f157"; } + +.fa.fa-rub { + --fa: "\f158"; } + +.fa.fa-ruble { + --fa: "\f158"; } + +.fa.fa-rouble { + --fa: "\f158"; } + +.fa.fa-krw { + --fa: "\f159"; } + +.fa.fa-won { + --fa: "\f159"; } + +.fa.fa-btc { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bitcoin { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bitcoin { + --fa: "\f15a"; } + +.fa.fa-file-text { + --fa: "\f15c"; } + +.fa.fa-sort-alpha-asc { + --fa: "\f15d"; } + +.fa.fa-sort-alpha-desc { + --fa: "\f881"; } + +.fa.fa-sort-amount-asc { + --fa: "\f884"; } + +.fa.fa-sort-amount-desc { + --fa: "\f160"; } + +.fa.fa-sort-numeric-asc { + --fa: "\f162"; } + +.fa.fa-sort-numeric-desc { + --fa: "\f886"; } + +.fa.fa-youtube-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-youtube-square { + --fa: "\f431"; } + +.fa.fa-youtube { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-xing { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-xing-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-xing-square { + --fa: "\f169"; } + +.fa.fa-youtube-play { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-youtube-play { + --fa: "\f167"; } + +.fa.fa-dropbox { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-stack-overflow { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-instagram { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-flickr { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-adn { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bitbucket { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bitbucket-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bitbucket-square { + --fa: "\f171"; } + +.fa.fa-tumblr { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-tumblr-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-tumblr-square { + --fa: "\f174"; } + +.fa.fa-long-arrow-down { + --fa: "\f309"; } + +.fa.fa-long-arrow-up { + --fa: "\f30c"; } + +.fa.fa-long-arrow-left { + --fa: "\f30a"; } + +.fa.fa-long-arrow-right { + --fa: "\f30b"; } + +.fa.fa-apple { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-windows { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-android { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-linux { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-dribbble { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-skype { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-foursquare { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-trello { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gratipay { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gittip { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gittip { + --fa: "\f184"; } + +.fa.fa-sun-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-sun-o { + --fa: "\f185"; } + +.fa.fa-moon-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-moon-o { + --fa: "\f186"; } + +.fa.fa-vk { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-weibo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-renren { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pagelines { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-stack-exchange { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-right { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-right { + --fa: "\f35a"; } + +.fa.fa-arrow-circle-o-left { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-left { + --fa: "\f359"; } + +.fa.fa-caret-square-o-left { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-left { + --fa: "\f191"; } + +.fa.fa-toggle-left { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-toggle-left { + --fa: "\f191"; } + +.fa.fa-dot-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-dot-circle-o { + --fa: "\f192"; } + +.fa.fa-vimeo-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-vimeo-square { + --fa: "\f194"; } + +.fa.fa-try { + --fa: "\e2bb"; } + +.fa.fa-turkish-lira { + --fa: "\e2bb"; } + +.fa.fa-plus-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-plus-square-o { + --fa: "\f0fe"; } + +.fa.fa-slack { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wordpress { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-openid { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-institution { + --fa: "\f19c"; } + +.fa.fa-bank { + --fa: "\f19c"; } + +.fa.fa-mortar-board { + --fa: "\f19d"; } + +.fa.fa-yahoo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-reddit { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-reddit-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-reddit-square { + --fa: "\f1a2"; } + +.fa.fa-stumbleupon-circle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-stumbleupon { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-delicious { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-digg { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pied-piper-pp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pied-piper-alt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-drupal { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-joomla { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-behance { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-behance-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-behance-square { + --fa: "\f1b5"; } + +.fa.fa-steam { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-steam-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-steam-square { + --fa: "\f1b7"; } + +.fa.fa-automobile { + --fa: "\f1b9"; } + +.fa.fa-cab { + --fa: "\f1ba"; } + +.fa.fa-spotify { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-deviantart { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-soundcloud { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-file-pdf-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-pdf-o { + --fa: "\f1c1"; } + +.fa.fa-file-word-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-word-o { + --fa: "\f1c2"; } + +.fa.fa-file-excel-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-excel-o { + --fa: "\f1c3"; } + +.fa.fa-file-powerpoint-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-powerpoint-o { + --fa: "\f1c4"; } + +.fa.fa-file-image-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-image-o { + --fa: "\f1c5"; } + +.fa.fa-file-photo-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-photo-o { + --fa: "\f1c5"; } + +.fa.fa-file-picture-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-picture-o { + --fa: "\f1c5"; } + +.fa.fa-file-archive-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-archive-o { + --fa: "\f1c6"; } + +.fa.fa-file-zip-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-zip-o { + --fa: "\f1c6"; } + +.fa.fa-file-audio-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-audio-o { + --fa: "\f1c7"; } + +.fa.fa-file-sound-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-sound-o { + --fa: "\f1c7"; } + +.fa.fa-file-video-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-video-o { + --fa: "\f1c8"; } + +.fa.fa-file-movie-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-movie-o { + --fa: "\f1c8"; } + +.fa.fa-file-code-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-code-o { + --fa: "\f1c9"; } + +.fa.fa-vine { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-codepen { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-jsfiddle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-life-bouy { + --fa: "\f1cd"; } + +.fa.fa-life-buoy { + --fa: "\f1cd"; } + +.fa.fa-life-saver { + --fa: "\f1cd"; } + +.fa.fa-support { + --fa: "\f1cd"; } + +.fa.fa-circle-o-notch { + --fa: "\f1ce"; } + +.fa.fa-rebel { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-ra { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-ra { + --fa: "\f1d0"; } + +.fa.fa-resistance { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-resistance { + --fa: "\f1d0"; } + +.fa.fa-empire { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-ge { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-ge { + --fa: "\f1d1"; } + +.fa.fa-git-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-git-square { + --fa: "\f1d2"; } + +.fa.fa-git { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-hacker-news { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-y-combinator-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-y-combinator-square { + --fa: "\f1d4"; } + +.fa.fa-yc-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-yc-square { + --fa: "\f1d4"; } + +.fa.fa-tencent-weibo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-qq { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-weixin { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wechat { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wechat { + --fa: "\f1d7"; } + +.fa.fa-send { + --fa: "\f1d8"; } + +.fa.fa-paper-plane-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-paper-plane-o { + --fa: "\f1d8"; } + +.fa.fa-send-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-send-o { + --fa: "\f1d8"; } + +.fa.fa-circle-thin { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-circle-thin { + --fa: "\f111"; } + +.fa.fa-header { + --fa: "\f1dc"; } + +.fa.fa-futbol-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-futbol-o { + --fa: "\f1e3"; } + +.fa.fa-soccer-ball-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-soccer-ball-o { + --fa: "\f1e3"; } + +.fa.fa-slideshare { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-twitch { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-yelp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-newspaper-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-newspaper-o { + --fa: "\f1ea"; } + +.fa.fa-paypal { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-wallet { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-visa { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-mastercard { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-discover { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-amex { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-paypal { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-stripe { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bell-slash-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-bell-slash-o { + --fa: "\f1f6"; } + +.fa.fa-trash { + --fa: "\f2ed"; } + +.fa.fa-copyright { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-eyedropper { + --fa: "\f1fb"; } + +.fa.fa-area-chart { + --fa: "\f1fe"; } + +.fa.fa-pie-chart { + --fa: "\f200"; } + +.fa.fa-line-chart { + --fa: "\f201"; } + +.fa.fa-lastfm { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-lastfm-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-lastfm-square { + --fa: "\f203"; } + +.fa.fa-ioxhost { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-angellist { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-cc { + --fa: "\f20a"; } + +.fa.fa-ils { + --fa: "\f20b"; } + +.fa.fa-shekel { + --fa: "\f20b"; } + +.fa.fa-sheqel { + --fa: "\f20b"; } + +.fa.fa-buysellads { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-connectdevelop { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-dashcube { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-forumbee { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-leanpub { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-sellsy { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-shirtsinbulk { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-simplybuilt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-skyatlas { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-diamond { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-diamond { + --fa: "\f3a5"; } + +.fa.fa-transgender { + --fa: "\f224"; } + +.fa.fa-intersex { + --fa: "\f224"; } + +.fa.fa-transgender-alt { + --fa: "\f225"; } + +.fa.fa-facebook-official { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-facebook-official { + --fa: "\f09a"; } + +.fa.fa-pinterest-p { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-whatsapp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-hotel { + --fa: "\f236"; } + +.fa.fa-viacoin { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-medium { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-y-combinator { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-yc { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-yc { + --fa: "\f23b"; } + +.fa.fa-optin-monster { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-opencart { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-expeditedssl { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-battery-4 { + --fa: "\f240"; } + +.fa.fa-battery { + --fa: "\f240"; } + +.fa.fa-battery-3 { + --fa: "\f241"; } + +.fa.fa-battery-2 { + --fa: "\f242"; } + +.fa.fa-battery-1 { + --fa: "\f243"; } + +.fa.fa-battery-0 { + --fa: "\f244"; } + +.fa.fa-object-group { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-object-ungroup { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-sticky-note-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-sticky-note-o { + --fa: "\f249"; } + +.fa.fa-cc-jcb { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-diners-club { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-clone { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hourglass-o { + --fa: "\f254"; } + +.fa.fa-hourglass-1 { + --fa: "\f251"; } + +.fa.fa-hourglass-2 { + --fa: "\f252"; } + +.fa.fa-hourglass-3 { + --fa: "\f253"; } + +.fa.fa-hand-rock-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-rock-o { + --fa: "\f255"; } + +.fa.fa-hand-grab-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-grab-o { + --fa: "\f255"; } + +.fa.fa-hand-paper-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-paper-o { + --fa: "\f256"; } + +.fa.fa-hand-stop-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-stop-o { + --fa: "\f256"; } + +.fa.fa-hand-scissors-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-scissors-o { + --fa: "\f257"; } + +.fa.fa-hand-lizard-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-lizard-o { + --fa: "\f258"; } + +.fa.fa-hand-spock-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-spock-o { + --fa: "\f259"; } + +.fa.fa-hand-pointer-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-pointer-o { + --fa: "\f25a"; } + +.fa.fa-hand-peace-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-peace-o { + --fa: "\f25b"; } + +.fa.fa-registered { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-creative-commons { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gg { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gg-circle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-odnoklassniki { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-odnoklassniki-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-odnoklassniki-square { + --fa: "\f264"; } + +.fa.fa-get-pocket { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wikipedia-w { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-safari { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-chrome { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-firefox { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-opera { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-internet-explorer { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-television { + --fa: "\f26c"; } + +.fa.fa-contao { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-500px { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-amazon { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-calendar-plus-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-calendar-plus-o { + --fa: "\f271"; } + +.fa.fa-calendar-minus-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-calendar-minus-o { + --fa: "\f272"; } + +.fa.fa-calendar-times-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-calendar-times-o { + --fa: "\f273"; } + +.fa.fa-calendar-check-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-calendar-check-o { + --fa: "\f274"; } + +.fa.fa-map-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-map-o { + --fa: "\f279"; } + +.fa.fa-commenting { + --fa: "\f4ad"; } + +.fa.fa-commenting-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-commenting-o { + --fa: "\f4ad"; } + +.fa.fa-houzz { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-vimeo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-vimeo { + --fa: "\f27d"; } + +.fa.fa-black-tie { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-fonticons { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-reddit-alien { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-edge { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-credit-card-alt { + --fa: "\f09d"; } + +.fa.fa-codiepie { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-modx { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-fort-awesome { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-usb { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-product-hunt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-mixcloud { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-scribd { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pause-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-pause-circle-o { + --fa: "\f28b"; } + +.fa.fa-stop-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-stop-circle-o { + --fa: "\f28d"; } + +.fa.fa-bluetooth { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bluetooth-b { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gitlab { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wpbeginner { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wpforms { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-envira { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wheelchair-alt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wheelchair-alt { + --fa: "\f368"; } + +.fa.fa-question-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-question-circle-o { + --fa: "\f059"; } + +.fa.fa-volume-control-phone { + --fa: "\f2a0"; } + +.fa.fa-asl-interpreting { + --fa: "\f2a3"; } + +.fa.fa-deafness { + --fa: "\f2a4"; } + +.fa.fa-hard-of-hearing { + --fa: "\f2a4"; } + +.fa.fa-glide { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-glide-g { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-signing { + --fa: "\f2a7"; } + +.fa.fa-viadeo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-viadeo-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-viadeo-square { + --fa: "\f2aa"; } + +.fa.fa-snapchat { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-snapchat-ghost { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-snapchat-ghost { + --fa: "\f2ab"; } + +.fa.fa-snapchat-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-snapchat-square { + --fa: "\f2ad"; } + +.fa.fa-pied-piper { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-first-order { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-yoast { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-themeisle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-plus-official { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-plus-official { + --fa: "\f2b3"; } + +.fa.fa-google-plus-circle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-plus-circle { + --fa: "\f2b3"; } + +.fa.fa-font-awesome { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-fa { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-fa { + --fa: "\f2b4"; } + +.fa.fa-handshake-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-handshake-o { + --fa: "\f2b5"; } + +.fa.fa-envelope-open-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-envelope-open-o { + --fa: "\f2b6"; } + +.fa.fa-linode { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-address-book-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-address-book-o { + --fa: "\f2b9"; } + +.fa.fa-vcard { + --fa: "\f2bb"; } + +.fa.fa-address-card-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-address-card-o { + --fa: "\f2bb"; } + +.fa.fa-vcard-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-vcard-o { + --fa: "\f2bb"; } + +.fa.fa-user-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-user-circle-o { + --fa: "\f2bd"; } + +.fa.fa-user-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-user-o { + --fa: "\f007"; } + +.fa.fa-id-badge { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-drivers-license { + --fa: "\f2c2"; } + +.fa.fa-id-card-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-id-card-o { + --fa: "\f2c2"; } + +.fa.fa-drivers-license-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-drivers-license-o { + --fa: "\f2c2"; } + +.fa.fa-quora { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-free-code-camp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-telegram { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-thermometer-4 { + --fa: "\f2c7"; } + +.fa.fa-thermometer { + --fa: "\f2c7"; } + +.fa.fa-thermometer-3 { + --fa: "\f2c8"; } + +.fa.fa-thermometer-2 { + --fa: "\f2c9"; } + +.fa.fa-thermometer-1 { + --fa: "\f2ca"; } + +.fa.fa-thermometer-0 { + --fa: "\f2cb"; } + +.fa.fa-bathtub { + --fa: "\f2cd"; } + +.fa.fa-s15 { + --fa: "\f2cd"; } + +.fa.fa-window-maximize { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-window-restore { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-times-rectangle { + --fa: "\f410"; } + +.fa.fa-window-close-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-window-close-o { + --fa: "\f410"; } + +.fa.fa-times-rectangle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-times-rectangle-o { + --fa: "\f410"; } + +.fa.fa-bandcamp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-grav { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-etsy { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-imdb { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-ravelry { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-eercast { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-eercast { + --fa: "\f2da"; } + +.fa.fa-snowflake-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-snowflake-o { + --fa: "\f2dc"; } + +.fa.fa-superpowers { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wpexplorer { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-meetup { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +*, +*: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; } } +iframe[src*=disqus] { + color-scheme: light; } + +a { + font-weight: 500; + color: #1565c0; + text-decoration: none; + transition: all 0.25s ease-in; } + a:focus, a:hover { + text-decoration: underline; } + +p { + margin: 2rem 0 2rem 0; + white-space: pre-wrap; + white-space: -moz-pre-wrap; + white-space: -pre-wrap; + white-space: -o-pre-wrap; + word-wrap: break-word; } + @media only screen and (max-width: 768px) { + p { + margin: 1.5rem 0 1.5rem 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 0; } + 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: 2rem 0 2rem; + padding: 1rem; + border-radius: 1rem; + overflow-x: auto; } + +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: 2rem 0 2rem; + padding: 1rem; + border-radius: 1rem; } + 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; + border-radius: 0.6rem; + padding: 0.3rem 0.6rem; + background-color: #ccc; + color: #212121; } + @media only screen and (max-width: 768px) { + code { + font-size: 1.5rem; } } +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; } + +.footnotes ol li p { + margin: 0; } + +.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; } + +.content { + flex: 1; + display: flex; + margin-top: 1.6rem; + margin-bottom: 3.2rem; } + @media only screen and (max-width: 768px) { + .content { + margin-top: 1rem; + margin-bottom: 1.6rem; } } + .content header { + margin-top: 6.4rem; + margin-bottom: 3.2rem; } + .content header h1 { + font-size: 4.2rem; + line-height: 4.6rem; + margin: 0; } + @media only screen and (max-width: 768px) { + .content header h1 { + font-size: 4rem; + line-height: 4.4rem; } } + .content article a:where(.external-link):not(:has(img)):after { + content: "\f08e"; + padding-left: 0.5em; + font-size: 0.75em; } + .content article details summary { + cursor: pointer; } + .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; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; } + .content .post .post-title { + margin-bottom: 0.75em; } + .content .post .post-meta i { + text-align: center; + width: 1.6rem; + margin-left: 0; + margin-right: 0.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: 0.3rem 0.6rem; + background-color: #e0e0e0; + border-radius: 0.6rem; + line-height: 1.5em; } + .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: 17rem; } } +.list ul { + margin: 3.2rem 0 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 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: 0.5rem; } + .centered .about h2 { + margin-top: 1rem; + margin-bottom: 0.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 0; + padding: 0; + cursor: pointer; } + .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.5rem; } } + .centered .error { + text-align: center; } + .centered .error h1 { + margin-top: 2rem; + margin-bottom: 0.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: 0.2rem; + position: relative; + margin: 2rem 0; + padding: 0 0.75rem; + overflow: auto; } + .notice .notice-title { + position: relative; + font-weight: 700; + margin: 0 -0.75rem; + padding: 0.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 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: 0.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 0.25s, max-height 0.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 { + display: initial; + position: relative; + visibility: hidden; } + .navigation #menu-toggle:checked + label > i { + color: #e0e0e0; } + .navigation #menu-toggle:checked + label + ul { + visibility: visible; + opacity: 1; + max-height: 100rem; } + .navigation #menu-toggle:focus-visible + label { + outline-style: auto; } } + .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 { + display: flex; + justify-content: center; + 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; + padding: 0 5px 0 5px; + margin: 0; + text-align: center; + width: 2.2rem; } + .pagination li a { + font-weight: 300; } + +.tabs { + display: flex; + flex-wrap: wrap; + margin: 2rem 0 2rem 0; + position: relative; } + .tabs.tabs-left { + justify-content: flex-start; } + .tabs.tabs-left label.tab-label { + margin-right: 0.5rem; } + .tabs.tabs-left .tab-content { + border-radius: 0px 4px 4px 4px; } + .tabs.tabs-right { + justify-content: flex-end; } + .tabs.tabs-right label.tab-label { + margin-left: 0.5rem; } + .tabs.tabs-right .tab-content { + border-radius: 4px 0px 4px 4px; } + .tabs input.tab-input { + display: none; } + .tabs label.tab-label { + background-color: #e0e0e0; + border-color: #ccc; + border-radius: 4px 4px 0px 0px; + border-style: solid; + border-bottom-style: hidden; + border-width: 1px; + cursor: pointer; + display: inline-block; + order: 1; + padding: 0.3rem 0.6rem; + position: relative; + top: 1px; + user-select: none; } + .tabs input.tab-input:checked + label.tab-label { + background-color: #fafafa; } + .tabs .tab-content { + background-color: #fafafa; + border-color: #ccc; + border-style: solid; + border-width: 1px; + display: none; + order: 2; + padding: 1rem; + width: 100%; } + .tabs.tabs-code .tab-content { + padding: 0.5rem; } + .tabs.tabs-code .tab-content pre { + margin: 0; } + +.taxonomy li { + display: inline-block; + margin: 0.9rem; } + +.taxonomy .taxonomy-element { + display: block; + padding: 0.3rem 0.9rem; + background-color: #e0e0e0; + border-radius: 0.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; } + @media only screen and (max-width: 768px) { + .footer { + font-size: 1.5rem; } } + .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: 0.2rem; + opacity: 0.5; + transition: all 0.25s ease-in; } + .float-container a:hover, .float-container a:focus { + color: #1565c0; + opacity: 1; } + @media only screen and (max-width: 768px) { + .float-container a:hover, .float-container a:focus { + color: #000; + opacity: 0.5; } } + .float-container a i { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); } + +.mastodon-wrapper { + display: flex; + gap: 3rem; + flex-direction: row; } + +.comment-level { + max-width: 3rem; + min-width: 3rem; } + +.reply-original { + display: none; } + +.mastodon-comment { + background-color: var(--body-background); + border-radius: var(--card-border-radius); + padding: var(--card-padding); + margin-bottom: 1rem; + display: flex; + gap: 1rem; + flex-direction: column; + flex-grow: 2; } + .mastodon-comment .comment { + display: flex; + flex-direction: row; + gap: 1rem; + flex-wrap: true; } + .mastodon-comment .comment-avatar img { + width: 6rem; } + .mastodon-comment .content { + flex-grow: 2; } + .mastodon-comment .comment-author { + display: flex; + flex-direction: column; } + .mastodon-comment .comment-author-name { + font-weight: bold; } + .mastodon-comment .comment-author-name a { + display: flex; + align-items: center; } + .mastodon-comment .comment-author-date { + margin-left: auto; } + .mastodon-comment .disabled { + color: var(--accent-color); } + +.mastodon-comment-content p:first-child { + margin-top: 0; } + +.mastodon { + --dlg-bg: #282c37; + --dlg-w: 600px; + --dlg-color: #9baec8; + --dlg-button-p: 0.75em 2em; + --dlg-outline-c: #00D9F5; } + +/* Background */ +.bg { + background-color: #ffffff; } + +/* PreWrapper */ +.chroma { + background-color: #ffffff; } + +/* Other */ +/* Error */ +.chroma .err { + color: #a61717; + background-color: #e3d2d2; } + +/* CodeLine */ +/* LineLink */ +.chroma .lnlinks { + outline: none; + text-decoration: none; + color: inherit; } + +/* LineTableTD */ +.chroma .lntd { + vertical-align: top; + padding: 0; + margin: 0; + border: 0; } + +/* LineTable */ +.chroma .lntable { + border-spacing: 0; + padding: 0; + margin: 0; + border: 0; } + +/* LineHighlight */ +.chroma .hl { + background-color: #ffffcc; } + +/* LineNumbersTable */ +.chroma .lnt { + white-space: pre; + user-select: none; + margin-right: 0.4em; + padding: 0 0.4em 0 0.4em; + color: #7f7f7f; } + +/* LineNumbers */ +.chroma .ln { + white-space: pre; + user-select: none; + margin-right: 0.4em; + padding: 0 0.4em 0 0.4em; + color: #7f7f7f; } + +/* Line */ +.chroma .line { + display: flex; } + +/* Keyword */ +.chroma .k { + color: #000000; + font-weight: bold; } + +/* KeywordConstant */ +.chroma .kc { + color: #000000; + font-weight: bold; } + +/* KeywordDeclaration */ +.chroma .kd { + color: #000000; + font-weight: bold; } + +/* KeywordNamespace */ +.chroma .kn { + color: #000000; + font-weight: bold; } + +/* KeywordPseudo */ +.chroma .kp { + color: #000000; + font-weight: bold; } + +/* KeywordReserved */ +.chroma .kr { + color: #000000; + font-weight: bold; } + +/* KeywordType */ +.chroma .kt { + color: #445588; + font-weight: bold; } + +/* Name */ +/* NameAttribute */ +.chroma .na { + color: #008080; } + +/* NameBuiltin */ +.chroma .nb { + color: #0086b3; } + +/* NameBuiltinPseudo */ +.chroma .bp { + color: #999999; } + +/* NameClass */ +.chroma .nc { + color: #445588; + font-weight: bold; } + +/* NameConstant */ +.chroma .no { + color: #008080; } + +/* NameDecorator */ +.chroma .nd { + color: #3c5d5d; + font-weight: bold; } + +/* NameEntity */ +.chroma .ni { + color: #800080; } + +/* NameException */ +.chroma .ne { + color: #990000; + font-weight: bold; } + +/* NameFunction */ +.chroma .nf { + color: #990000; + font-weight: bold; } + +/* NameFunctionMagic */ +/* NameLabel */ +.chroma .nl { + color: #990000; + font-weight: bold; } + +/* NameNamespace */ +.chroma .nn { + color: #555555; } + +/* NameOther */ +/* NameProperty */ +/* NameTag */ +.chroma .nt { + color: #000080; } + +/* NameVariable */ +.chroma .nv { + color: #008080; } + +/* NameVariableClass */ +.chroma .vc { + color: #008080; } + +/* NameVariableGlobal */ +.chroma .vg { + color: #008080; } + +/* NameVariableInstance */ +.chroma .vi { + color: #008080; } + +/* NameVariableMagic */ +/* Literal */ +/* LiteralDate */ +/* LiteralString */ +.chroma .s { + color: #dd1144; } + +/* LiteralStringAffix */ +.chroma .sa { + color: #dd1144; } + +/* LiteralStringBacktick */ +.chroma .sb { + color: #dd1144; } + +/* LiteralStringChar */ +.chroma .sc { + color: #dd1144; } + +/* LiteralStringDelimiter */ +.chroma .dl { + color: #dd1144; } + +/* LiteralStringDoc */ +.chroma .sd { + color: #dd1144; } + +/* LiteralStringDouble */ +.chroma .s2 { + color: #dd1144; } + +/* LiteralStringEscape */ +.chroma .se { + color: #dd1144; } + +/* LiteralStringHeredoc */ +.chroma .sh { + color: #dd1144; } + +/* LiteralStringInterpol */ +.chroma .si { + color: #dd1144; } + +/* LiteralStringOther */ +.chroma .sx { + color: #dd1144; } + +/* LiteralStringRegex */ +.chroma .sr { + color: #009926; } + +/* LiteralStringSingle */ +.chroma .s1 { + color: #dd1144; } + +/* LiteralStringSymbol */ +.chroma .ss { + color: #990073; } + +/* LiteralNumber */ +.chroma .m { + color: #009999; } + +/* LiteralNumberBin */ +.chroma .mb { + color: #009999; } + +/* LiteralNumberFloat */ +.chroma .mf { + color: #009999; } + +/* LiteralNumberHex */ +.chroma .mh { + color: #009999; } + +/* LiteralNumberInteger */ +.chroma .mi { + color: #009999; } + +/* LiteralNumberIntegerLong */ +.chroma .il { + color: #009999; } + +/* LiteralNumberOct */ +.chroma .mo { + color: #009999; } + +/* Operator */ +.chroma .o { + color: #000000; + font-weight: bold; } + +/* OperatorWord */ +.chroma .ow { + color: #000000; + font-weight: bold; } + +/* Punctuation */ +/* Comment */ +.chroma .c { + color: #999988; + font-style: italic; } + +/* CommentHashbang */ +.chroma .ch { + color: #999988; + font-style: italic; } + +/* CommentMultiline */ +.chroma .cm { + color: #999988; + font-style: italic; } + +/* CommentSingle */ +.chroma .c1 { + color: #999988; + font-style: italic; } + +/* CommentSpecial */ +.chroma .cs { + color: #999999; + font-weight: bold; + font-style: italic; } + +/* CommentPreproc */ +.chroma .cp { + color: #999999; + font-weight: bold; + font-style: italic; } + +/* CommentPreprocFile */ +.chroma .cpf { + color: #999999; + font-weight: bold; + font-style: italic; } + +/* Generic */ +/* GenericDeleted */ +.chroma .gd { + color: #000000; + background-color: #ffdddd; } + +/* GenericEmph */ +.chroma .ge { + color: #000000; + font-style: italic; } + +/* GenericError */ +.chroma .gr { + color: #aa0000; } + +/* GenericHeading */ +.chroma .gh { + color: #999999; } + +/* GenericInserted */ +.chroma .gi { + color: #000000; + background-color: #ddffdd; } + +/* GenericOutput */ +.chroma .go { + color: #888888; } + +/* GenericPrompt */ +.chroma .gp { + color: #555555; } + +/* GenericStrong */ +.chroma .gs { + font-weight: bold; } + +/* GenericSubheading */ +.chroma .gu { + color: #aaaaaa; } + +/* GenericTraceback */ +.chroma .gt { + color: #aa0000; } + +/* GenericUnderline */ +.chroma .gl { + text-decoration: underline; } + +/* TextWhitespace */ +.chroma .w { + color: #bbbbbb; } + +/*# sourceMappingURL=coder.css.map */ \ No newline at end of file diff --git a/resources/_gen/assets/scss/coder.scss_d9b60ee5c2bc7799a5af2e1647965a29.json b/resources/_gen/assets/scss/coder.scss_d9b60ee5c2bc7799a5af2e1647965a29.json new file mode 100644 index 00000000..cfa430e8 --- /dev/null +++ b/resources/_gen/assets/scss/coder.scss_d9b60ee5c2bc7799a5af2e1647965a29.json @@ -0,0 +1 @@ +{"Target":"css/coder.css","MediaType":"text/css","Data":{}} \ No newline at end of file diff --git a/themes/anubis b/themes/anubis index 769fbb55..d1905a64 160000 --- a/themes/anubis +++ b/themes/anubis @@ -1 +1 @@ -Subproject commit 769fbb55e3eae5b6c839a2152c60c348521a4f1e +Subproject commit d1905a64250ef78b549af7ce2dff4ba8f0646ea7 diff --git a/themes/anubis2 b/themes/anubis2 new file mode 160000 index 00000000..0500942d --- /dev/null +++ b/themes/anubis2 @@ -0,0 +1 @@ +Subproject commit 0500942ded9bee0dd7fba9d413c7e31bed66cc7e diff --git a/themes/black-and-light b/themes/black-and-light new file mode 160000 index 00000000..e024de78 --- /dev/null +++ b/themes/black-and-light @@ -0,0 +1 @@ +Subproject commit e024de785b913e6ccc054ac6f062068d34e700cd diff --git a/themes/hugo-coder b/themes/hugo-coder new file mode 160000 index 00000000..5607e44d --- /dev/null +++ b/themes/hugo-coder @@ -0,0 +1 @@ +Subproject commit 5607e44d8c8f56b8b0389a0fb05a3ec4fb31d9ef